﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;
using System.Threading;
using System.Runtime.InteropServices;
using System.DirectoryServices;
using System.Net.NetworkInformation;
using System.Net;
using System.Net.Sockets;
using System.Linq;
using System.Globalization;
using System.Resources;
using System.Reflection;
using OpenCLNet;
using CL = OpenCLNet;
using Emgu.CV.GPU;
using Emgu.CV.Structure;
using Emgu.CV;

[assembly: CLSCompliant(true)]
namespace ImageResizerGPGPU
{
    public partial class MainForm : Form
    {
        static ImageCodecInfo[] imageCodecs = null;
        static string fileNameOpenFilter = string.Empty;
        static string fileNameSaveFilter = string.Empty; 
        static string path;
        static int[] oneImageCodec = new int[2];
        static string save_folder_path = string.Empty;
        static bool one_image = false;
        static EncoderParameters myEncoderParameters = new EncoderParameters(5);
        static bool overwrite = false;
        static int height = 0;
        static int width = 0;
        static Int64 q = 90;   
        static bool I_AM_IDLE = true;
        static CUDA CUDA_OBJECT = new CUDA();
        static bool MASTER = true;
        static EncoderParameter compression_par = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionLZW);
        static EncoderParameter ColorDepth_par = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 32L);
        static EncoderParameter RenderMethod_par = new EncoderParameter(System.Drawing.Imaging.Encoder.RenderMethod, (long)EncoderValue.RenderNonProgressive);
        static EncoderParameter ScanMethod_par = new EncoderParameter(System.Drawing.Imaging.Encoder.ScanMethod, (long)EncoderValue.ScanMethodNonInterlaced); 
        static ListOfBgWorkers workingThreads;
        static NetworkController NetworkControlerObject;
        static string addSlash = "/";
        static string procent = "%";
        static OpenCLNet.Platform oclPlatform;
        static OpenCLNet.Device[] oclDevices;
        static OpenCLNet.Device oclDevice;
        static  OpenCLNet.Context oclContext;
        static OpenCLNet.CommandQueue oclCQ;
        static ContextNotify oclContextNotify;
        static OpenCLNet.Program oclProgram;
        static Kernel FilterKernel;
        static List<string> CallBackEventList = new List<string>();
        static Sampler OCLSampler;
        static bool openCLInitialized = false;
        static bool THREADS_ARE_PAUSED = false;
        static bool DISPOSED = false;
        static Color[] mainBackgroundColor = {Color.SteelBlue, Color.FromArgb(98,0,124)};
        static bool initialized = false;
        static bool scanningFiles = false;       
        static int settingsOffset = 10;
        public static CultureInfo myLanguage;
        public static SortSettings _sortSettings;
        private static MainForm _instance = null;
        static int lastProgressUpdate = 0;
        public struct SortSettings 
        {
            public bool sortByYear;
            public bool sortByMonth;
            public bool sortByWeek;
            public bool sortByDay;
            public bool scanFileInfo;
        }
        private MainForm(string[] args)
        {           
            InitializeComponent();
            initializeOpenCL();
            setSettingsTitles();
            registerSettingsEvents();
            initializeSettings();
            this.toggleSettingsButton.initialize(this, string.Empty);
            imageCodecs = ImageCodecInfo.GetImageDecoders();         
            listCodecsForFileFilter();          
            this.textBoxImageHeight.Text = addSlash;
            NetworkControlerObject = new NetworkController(true, this);
            progressPicturesBox.Paint += progressPicturesBox_Paint;
            this.DragDrop += MainForm_DragDrop;
            this.DragEnter += MainForm_DragEnter;
            this.DragLeave += MainForm_DragLeave;
            this.FormClosed += MainForm_FormClosed;       
            start.ForeColor = mainBackgroundColor[1];
            int openedHeight = saveCurrentStateButton.Location.Y + saveCurrentStateButton.Height  + settingsOffset;// this.ClientSize.Height;
            this.ClientSize = new Size(this.ClientSize.Width, toggleSettingsButton.Location.Y + toggleSettingsButton.Height + settingsOffset - toggleSettingsButton.MarginBottom - toggleSettingsButton.MarginTop);
            int closedHeight = this.ClientSize.Height;
            toggleSettingsButton.setHeightClosedOpened(closedHeight, openedHeight);
            MenuItemsRegisterTextChange();
            if (args != null)
            {
                if (args.Length > 0)
                {
                    MainForm_DragDrop(null, new DragEventArgs(new DataObject(DataFormats.FileDrop, args), 0, 0, 0, DragDropEffects.Copy, DragDropEffects.Copy));
                }
            }
            initialized = true;
            _instance = this;
        }

        void ignoreSubFoldersCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.ignoreSubFolders = ignoreSubFoldersCheckBox.Checked;          
        }
       
        public static MainForm Instance(string[] args = null)
        {
            if (_instance == null)
            {
                return new MainForm(args);
            }
            else
            {
                return _instance;
            }
        }
        public int RealLeft
        {
            get
            {               
                return (this.Size.Width - this.ClientSize.Width)/2 + this.Location.X;
            }
        }
        void MenuItemsRegisterTextChange()
        {
            for (int i = 0; i < mainMenuStrip.Items.Count; i++)
            {
                mainMenuStrip.Items[i].TextChanged += MainForm_TextChanged;
            }
            RefreshMenuStripChange();
        }

        void MainForm_TextChanged(object sender, EventArgs e)
        {
            RefreshMenuStripChange();
        }
        void RefreshMenuStripChange()
        {
            int menuTakenWidth = GetMenuItemsWidth();
            progressPicturesBox.Left = menuTakenWidth;
            progressPicturesBox.Width = this.Width - menuTakenWidth;
            progressPicturesBox.Height = mainMenuStrip.Height;
            progressPicturesBox.Invalidate();
        }
        int GetMenuItemsWidth()
        {
            int itemsWidth=0;
            for (int i = 0; i < mainMenuStrip.Items.Count; i++)
            {
                itemsWidth += mainMenuStrip.Items[i].Width;
            }
            return itemsWidth+10;
        }
        void sortByYearCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            _sortSettings.sortByYear = sortByYearCheckBox.Checked;
            ImageResizerGPGPU.Properties.Settings.Default.sortByYear = sortByYearCheckBox.Checked;
            checkSortSettings();
        }

        void sortByWeekCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            _sortSettings.sortByWeek = sortByWeekCheckBox.Checked;
            ImageResizerGPGPU.Properties.Settings.Default.sortByWeek = sortByWeekCheckBox.Checked;
            checkSortSettings();
        }

        void sortByMonthCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            _sortSettings.sortByMonth = sortByMonthCheckBox.Checked;
            ImageResizerGPGPU.Properties.Settings.Default.sortByMonth = sortByMonthCheckBox.Checked;
            checkSortSettings();
        }

        void sortByDayCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            _sortSettings.sortByDay = sortByDayCheckBox.Checked;
            ImageResizerGPGPU.Properties.Settings.Default.sortByDay = sortByDayCheckBox.Checked;
            checkSortSettings();
        }
        void alwaysOnTopCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.alwaysOnTop = alwaysOnTopCheckBox.Checked;           
            this.TopMost = alwaysOnTopCheckBox.Checked;            
        }
        void alwaysSaveAsJpeg_CheckedChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.alwaysSaveAsJpeg = alwaysSaveAsJpeg.Checked;
        }
        void workLocalCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.workLocal = workLocalCheckBox.Checked;           
            useDistrubutedCheckBox.Enabled = !ImageResizerGPGPU.Properties.Settings.Default.workLocal;            
        }
        void doNotUseMyPcDistributedCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.doUseMyPcDistributed = doNotUseMyPcDistributedCheckBox.Checked;
        }
        static string getResourceString(string resourceName, CultureInfo myLanguage)
        {
            return ImageResizerGPGPU.Properties.Resources.ResourceManager.GetString(resourceName, myLanguage);
        }
        void setSettingsTitles()
        {
            myLanguage = CultureInfo.InstalledUICulture; // new CultureInfo("en");
            alwaysOnTopCheckBox.Text = getResourceString("alwaysOnTopTitle", myLanguage);
            useDistrubutedCheckBox.Text = getResourceString("onlyDistributedPCsTitle", myLanguage);
            doNotUseMyPcDistributedCheckBox.Text = getResourceString("doNotUseMyPcDistributedTitle", myLanguage);
            alwaysSaveAsJpeg.Text = getResourceString("alwaysSaveAsJpegTitle", myLanguage);
            workLocalCheckBox.Text = getResourceString("workLocalLabelTitle", myLanguage);
            overwriteCheckBox.Text = getResourceString("overwriteLabelTitle", myLanguage);
            labelWidth.Text = getResourceString("WidthLabel", myLanguage);
            labelHeight.Text = getResourceString("HeightLabel", myLanguage);
            imageQualityLabel.Text = getResourceString("ImageQualityLabel", myLanguage);
            buttonSelectImage.Text = getResourceString("imageButton", myLanguage);
            buttonSelectFolder.Text = getResourceString("folderButton", myLanguage);
            selectToolStripMenuItemSelect.Text = getResourceString("selectButton", myLanguage);
            aboutToolStripMenuItem.Text = getResourceString("aboutButtonTitle", myLanguage);
            start.Text = getResourceString("StartButtonText", myLanguage);
            sortByYearCheckBox.Text = getResourceString("sortByYear", myLanguage);
            sortByMonthCheckBox.Text = getResourceString("sortByMonth", myLanguage);
            sortByWeekCheckBox.Text = getResourceString("sortByWeek", myLanguage);
            sortByDayCheckBox.Text = getResourceString("sortByDay", myLanguage);
            ignoreSubFoldersCheckBox.Text = getResourceString("ignoreSubFoldersTitle", myLanguage);
            GPUPriorityCheckBox.Text = getResourceString("GPUTitle", myLanguage);
            CPUPriorityCheckBox.Text = getResourceString("CPUTitle", myLanguage);
            engineLabel.Text = getResourceString("EnginePriority", myLanguage);
            sortLabel.Text = getResourceString("SortResults", myLanguage);
        }
        void registerSettingsEvents()
        {
            qualityTrackBar.ValueChanged += qualityTrackBar_ValueChanged;
            useDistrubutedCheckBox.CheckStateChanged += useDistrubutedCheckBox_CheckStateChanged;
            overwriteCheckBox.CheckedChanged += overwriteCheckBox_CheckedChanged;
            doNotUseMyPcDistributedCheckBox.CheckedChanged += doNotUseMyPcDistributedCheckBox_CheckedChanged;
            workLocalCheckBox.CheckedChanged += workLocalCheckBox_CheckedChanged;
            alwaysSaveAsJpeg.CheckedChanged += alwaysSaveAsJpeg_CheckedChanged;
            alwaysOnTopCheckBox.CheckedChanged += alwaysOnTopCheckBox_CheckedChanged;
            sortByDayCheckBox.CheckedChanged += sortByDayCheckBox_CheckedChanged;
            sortByMonthCheckBox.CheckedChanged += sortByMonthCheckBox_CheckedChanged;
            sortByWeekCheckBox.CheckedChanged += sortByWeekCheckBox_CheckedChanged;
            sortByYearCheckBox.CheckedChanged += sortByYearCheckBox_CheckedChanged;
            ignoreSubFoldersCheckBox.CheckedChanged += ignoreSubFoldersCheckBox_CheckedChanged;
            GPUPriorityCheckBox.CheckedChanged += GPUPriorityCheckBox_CheckedChanged;
            CPUPriorityCheckBox.CheckedChanged += CPUPriorityCheckBox_CheckedChanged;
        }

        void CPUPriorityCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.CPUPriority = CPUPriorityCheckBox.Checked;
            if (!ImageResizerGPGPU.Properties.Settings.Default.CPUPriority &&
               !ImageResizerGPGPU.Properties.Settings.Default.GPUPriority)
            {
                GPUPriorityCheckBox.Checked = true;
            }
            EngineChange();
        }

        void GPUPriorityCheckBox_CheckedChanged(object sender, EventArgs e)        
        {
            ImageResizerGPGPU.Properties.Settings.Default.GPUPriority = GPUPriorityCheckBox.Checked;
            if (!ImageResizerGPGPU.Properties.Settings.Default.CPUPriority &&
                !ImageResizerGPGPU.Properties.Settings.Default.GPUPriority)
            {
                CPUPriorityCheckBox.Checked = true;
            }
            EngineChange();
        }
        void initializeSettings()
        {
            SetWidthHeight(ImageResizerGPGPU.Properties.Settings.Default.width.ToString(CultureInfo.InvariantCulture),
               ImageResizerGPGPU.Properties.Settings.Default.height.ToString(CultureInfo.InvariantCulture),
               (int)ImageResizerGPGPU.Properties.Settings.Default.quality);
            overwriteCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.overwrite;
            useDistrubutedCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.useOnlyNetworkPCs;
            imageQualityLabel.Text = getResourceString("ImageQualityLabel", myLanguage) + qualityTrackBar.Value.ToString(CultureInfo.InvariantCulture) + procent;
            doNotUseMyPcDistributedCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.doUseMyPcDistributed;
            workLocalCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.workLocal;
            alwaysSaveAsJpeg.Checked = ImageResizerGPGPU.Properties.Settings.Default.alwaysSaveAsJpeg;
            alwaysOnTopCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.alwaysOnTop;
            this.TopMost = alwaysOnTopCheckBox.Checked;
            sortByDayCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.sortByDay;
            sortByMonthCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.sortByMonth;
            sortByWeekCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.sortByWeek;
            sortByYearCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.sortByYear;
            ignoreSubFoldersCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.ignoreSubFolders;
            GPUPriorityCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.GPUPriority;
            CPUPriorityCheckBox.Checked = ImageResizerGPGPU.Properties.Settings.Default.CPUPriority;
            _sortSettings.sortByDay = sortByDayCheckBox.Checked;
            _sortSettings.sortByWeek = sortByWeekCheckBox.Checked;
            _sortSettings.sortByMonth = sortByMonthCheckBox.Checked;
            _sortSettings.sortByYear = sortByYearCheckBox.Checked;
            checkSortSettings();
        }
        private void checkSortSettings()
        {
            if (_sortSettings.sortByYear || _sortSettings.sortByWeek || _sortSettings.sortByMonth || _sortSettings.sortByDay)
            {
                _sortSettings.scanFileInfo = true;
            }
            else
            {
                _sortSettings.scanFileInfo = false;
            }
        }
        static void setCurrentSettings()
        {
            ImageResizerGPGPU.Properties.Settings.Default.width = width;
            ImageResizerGPGPU.Properties.Settings.Default.height = height;
            ImageResizerGPGPU.Properties.Settings.Default.quality = q;
        }
        void overwriteCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.overwrite = overwriteCheckBox.Checked;    
        }     
        void useDistrubutedCheckBox_CheckStateChanged(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.useOnlyNetworkPCs = useDistrubutedCheckBox.Checked;
        }
        void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            DISPOSED = true;
            if (workingThreads != null)
            {
                workingThreads.Dispose();
            }
            if (NetworkControlerObject != null)
            {
                NetworkControlerObject.resetClass();
            }
        }
        void MainForm_DragLeave(object sender, EventArgs e)
        {
            this.BackColor = mainBackgroundColor[0];           
        }
        void MainForm_DragEnter(object sender, DragEventArgs e)
        {
            if (I_AM_IDLE && MASTER || !MASTER)
            {               
                e.Effect = DragDropEffects.Copy;
                this.BackColor = mainBackgroundColor[1];
            }
        }
        public static bool CompareDirectories(string directoryOne, string directoryTwo)
        {
            ListFiles data_0 = getFiles(directoryOne, null, null);
            ListFiles data_1 = getFiles(directoryTwo, null, null);
            return data_0.CompareListDirectories(data_1);
        }
        public bool GpuEnabledOnSystem
        {
            get
            {
                return (IsOpenCLEnabled || CUDA_OBJECT.CV_CUDA_ENABLED);
            }
        }
        class CUDA
        {
            string[] dependentDlls = { "cudart32_50_35", "cublas32_50_35", "cufft32_50_35", "cvextern", "npp32_50_35",
                                    "opencv_calib3d249", "opencv_contrib249", "opencv_core249","opencv_features2d249",
                                     "opencv_ffmpeg249", "opencv_flann249", "opencv_gpu249", "opencv_highgui249",
                                     "opencv_imgproc249", "opencv_legacy249", "opencv_ml249", "opencv_nonfree249",
                                     "opencv_objdetect249", "opencv_photo249", "opencv_stitching249", "opencv_video249",
                                     "opencv_videostab249","Emgu.CV.GPU", "Emgu.CV", "Emgu.Util"};
            internal static class NativeMethods
            {              
               [DllImport("cudaGetDeviceCount.dll", EntryPoint = "?IsCudaEnabled@@YAHXZ")]
                internal static extern int IsCudaEnabled();
            }
            bool USE_CV_CUDA = false;
            float CUDA_CORES_p = 0;
            bool firstTime = true;
            static bool cudaDLLNotFound = false;
            public bool CV_CUDA_ENABLED
            {
                get
                {
                    cudaRefresh();
                    return USE_CV_CUDA;
                }
            }
            private void cudaRefresh()
            {
                if (cudaDLLNotFound)
                {
                    USE_CV_CUDA = false;
                }
                else
                {
                    int CudaStatus = 0;
                   /*  using (Emgu.CV.GPU.GpuDeviceInfo info = new GpuDeviceInfo())
                      {
                      }*/
                    try
                    {
                        CudaStatus = NativeMethods.IsCudaEnabled();
                    }
                    catch (DllNotFoundException)
                    {
                        CudaStatus = 0;
                        cudaDLLNotFound = true;
                    }
                    finally
                    {
                        string[] filesInDir = Directory.GetFiles(Application.StartupPath);
                        for (int i = 0; i < dependentDlls.Length; i++)
                        {
                            bool found = false;
                            dependentDlls[i] += ".dll";
                            for (int a = 0; a < filesInDir.Length; a++)
                            {                                
                                if (dependentDlls[i].Equals(Path.GetFileName(filesInDir[a])))
                                {
                                    found = true;
                                    break;
                                }                               
                            }
                            if (!found)
                            {
                                cudaDLLNotFound = true;
                                break;
                            }
                        }
                    }
                    if (CudaStatus >= 1)
                    {
                        CUDA_CORES_p = CudaStatus;
                        if (!cudaDLLNotFound)
                        {
                            USE_CV_CUDA = true;
                            if (firstTime)
                            {
                                firstTime = false;
                                ThreadPool.QueueUserWorkItem(new WaitCallback(cudaDummyCall), null);
                            }
                        }
                    }
                    else
                    {
                        CUDA_CORES_p = 0;
                        USE_CV_CUDA = false;
                    }
                }
            }
            private static void cudaDummyCall(object shouldUseCV)
            {
                using (Bitmap loadedImage = new Bitmap(10, 10))
                {                    
                    using (Emgu.CV.Image<Rgba, Byte> slikaImg = new Emgu.CV.Image<Rgba, Byte>(loadedImage))
                    {
                        Emgu.CV.GPU.GpuImage<Rgba, Byte> slika = new Emgu.CV.GPU.GpuImage<Rgba, Byte>(slikaImg);
                        slika.Dispose();
                    }
                }
            }            
           public static Bitmap getResizedImage(Size pictureSize, Bitmap loadedImage)
            {
                Bitmap loadedImageTemp = null;
                try
                {
                    using (Emgu.CV.Image<Bgra, Byte> slikaImg = new Emgu.CV.Image<Bgra, Byte>(loadedImage))
                    {
                        using (Emgu.CV.GPU.GpuImage<Bgra, Byte> slika = new Emgu.CV.GPU.GpuImage<Bgra, Byte>(slikaImg))
                        {
                            using (Emgu.CV.GPU.Stream gpuStream = new Emgu.CV.GPU.Stream())
                            {
                                using (Emgu.CV.GPU.GpuImage<Bgra, Byte> slikaResized = slika.Resize(pictureSize, Emgu.CV.CvEnum.INTER.CV_INTER_AREA, gpuStream))
                                {
                                    Bitmap result = new Bitmap(slikaResized.Size.Width, slikaResized.Size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                                    System.Drawing.Imaging.BitmapData data = result.LockBits(new Rectangle(Point.Empty, result.Size),
                                        System.Drawing.Imaging.ImageLockMode.WriteOnly, result.PixelFormat);
                                    using (Emgu.CV.Image<Bgra, Byte> tmp = new Emgu.CV.Image<Bgra, Byte>(slikaResized.Size.Width, slikaResized.Size.Height, data.Stride, data.Scan0))
                                    {
                                        GpuInvoke.GpuMatDownload(slikaResized.Ptr, tmp);
                                    }
                                    result.UnlockBits(data);
                                    loadedImageTemp = result;
                                    loadedImage.Dispose();
                                    loadedImage = loadedImageTemp;
                                    loadedImageTemp = null;
                                }
                            }                           
                        }
                    }                   
                }
                finally
                {
                    if (loadedImageTemp != null)
                    {
                        loadedImageTemp.Dispose();
                    }
                }
                return loadedImage;
            }
            public int CUDA_CORES
            {
                get
                {
                    cudaRefresh();
                    if (CUDA_CORES_p > 0)
                    {
                        return (int)CUDA_CORES_p;
                    }
                    else if (OpenCL.NumberOfPlatforms > 0)
                    {
                       Platform GPUPlatform = OpenCL.GetPlatform(0);
                        Device[] MyDevices = GPUPlatform.QueryDevices(DeviceType.GPU);
                        if (MyDevices.Length > 0)
                        {
                            return (int)MyDevices[0].MaxComputeUnits;
                        }
                        else
                        {
                            return OpenCL.NumberOfPlatforms;
                        }
                    }
                    else
                    {
                        return 0;
                    }
                }
            }
        }
        static class CORE_SCALL_FACTORS
        {
            public static int GPU_MASTER
            {
                get
                {
                    if (ImageResizerGPGPU.Properties.Settings.Default.GPUPriority)
                    {
                        return 8;
                    }
                    else
                    {
                        return 0;
                    }
                }
            }
            public static int GPU_SLAVE
            {
                get
                {
                    return 1;
                }
            }
            public static int CPU_MASTER
            {
                get
                {
                    if (ImageResizerGPGPU.Properties.Settings.Default.CPUPriority)
                    {
                        return 1;
                    }
                    else
                    {
                        return 0;
                    }
                }
            }
            public static int CPU_SLAVE
            {
                get
                {
                    return 1;
                }
            }
        }
        void MainForm_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] dropedFiles = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (dropedFiles.Length > 1 || Directory.Exists(dropedFiles[0]))
                {                    
                    path = ((checkIfItIsDisk(dropedFiles[0])) ? dropedFiles[0] :  Path.GetDirectoryName(dropedFiles[0]));
                    one_image = false;
                    start_Click(new List<string>(dropedFiles), null);
                }
                else
                {
                  
                    path = dropedFiles[0];
                    one_image = true;
                    start_Click(null,null);                   
                }
                this.BackColor = mainBackgroundColor[0];
            }
        }
        private static void CLDummyCall(object none)
        {
            using (Bitmap loadedImage = new Bitmap(10, 10))
            {
                CreateOpenCLImages(loadedImage, new Size(10, 10));
            }
        }            
       static void initializeOpenCL()
        {
            if (!CUDA_OBJECT.CV_CUDA_ENABLED && OpenCL.NumberOfPlatforms > 0)
            {
                try
                {
                    oclContextNotify = new ContextNotify(OpenCLContextNotifyCallback);
                    oclPlatform = OpenCL.GetPlatform(0);
                    oclDevices = oclPlatform.QueryDevices(DeviceType.ALL);
                    oclDevice = oclDevices[0];
                    CreateContext(oclPlatform, oclDevice);
                    bool supportsImageFormat = oclContext.SupportsImageFormat(MemFlags.READ_WRITE, MemObjectType.IMAGE2D, ChannelOrder.RGBA, ChannelType.UNSIGNED_INT8);
                    if (oclDevice.ImageSupport && supportsImageFormat)
                    {
                        BuildOpenCLSource(File.ReadAllText(@"OpenCLFunctions.cl"));
                        ThreadPool.QueueUserWorkItem(new WaitCallback(CLDummyCall), null);
                        openCLInitialized = true;
                    }
                }
                catch (OpenCLException)
                {
                    openCLInitialized = false;
                }
            }
            else
            {
                openCLInitialized = false;
            }
        }
        public static bool IsOpenCLEnabled
        {
            get
            {
                return openCLInitialized;                
            }
        }
        public static Bitmap CreateOpenCLImages(Bitmap testImage, Size sizeOfResizedImage)
        {
            Bitmap outputImg = null;
            Bitmap outputImgTemp = null;
            if (testImage != null)
            {
                try
                {
                    using (CL.Image OCLInputImage = CreateOpenCLBitmapFromBitmap(testImage))
                    {                        
                        CL.ImageFormat clImageFormat = new CL.ImageFormat(CL.ChannelOrder.RGBA, CL.ChannelType.UNSIGNED_INT8);
                        CL.Image OCLOutputImage = oclContext.CreateImage2D(MemFlags.WRITE_ONLY, clImageFormat, sizeOfResizedImage.Width, sizeOfResizedImage.Height, 0, IntPtr.Zero);
                        OCLSampler = oclContext.CreateSampler(true, AddressingMode.CLAMP_TO_EDGE, FilterMode.LINEAR);
                        outputImgTemp = new Bitmap(sizeOfResizedImage.Width, sizeOfResizedImage.Height, PixelFormat.Format32bppArgb);
                        ScaleImage(outputImgTemp, OCLOutputImage, OCLInputImage);
                        OCLOutputImage.Dispose();
                        outputImg = outputImgTemp;
                        outputImgTemp = null;
                    }
                    testImage.Dispose();
                }
                finally
                {
                    if (outputImgTemp != null)
                    {
                        outputImgTemp.Dispose();
                    }
                }
            }
            return outputImg;
        }
        public static CL.Image CreateOpenCLBitmapFromBitmap(Bitmap bitmap)
        {
            CL.Image oclImage = null;          
            if (bitmap != null)
            {
                lock (bitmap)
                {
                    BitmapData bd = null;
                    try
                    {
                        CL.ImageFormat clImageFormat = new CL.ImageFormat(CL.ChannelOrder.RGBA, CL.ChannelType.UNSIGNED_INT8);
                        bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                        oclImage = oclContext.CreateImage2D((MemFlags)((long)MemFlags.READ_ONLY | (long)MemFlags.COPY_HOST_PTR),
                        clImageFormat, bd.Width, bd.Height, bd.Stride, bd.Scan0);
                    }
                    finally
                    {
                        bitmap.UnlockBits(bd);
                    }
                }
                
            }          
            return oclImage;
        }
        public static void ScaleImage(Bitmap testImageOutput, CL.Mem openCLOutputImage, CL.Mem openCLInputImage)
        {
            if (testImageOutput != null)
            {
                IntPtr[] globalWorkSize = new IntPtr[3];
                globalWorkSize[0] = (IntPtr)testImageOutput.Width;
                globalWorkSize[1] = (IntPtr)testImageOutput.Height;
                FilterKernel.SetArg(0, 0.0f);
                FilterKernel.SetArg(1, 0.0f);
                FilterKernel.SetArg(2, 1.0f);
                FilterKernel.SetArg(3, 1.0f);
                FilterKernel.SetArg(4, 0.0f);
                FilterKernel.SetArg(5, 0.0f);
                FilterKernel.SetArg(6, 1.0f);
                FilterKernel.SetArg(7, 1.0f);
                FilterKernel.SetArg(8, openCLInputImage);
                FilterKernel.SetArg(9, openCLOutputImage);
                FilterKernel.SetArg(10, OCLSampler);
                oclCQ.EnqueueNDRangeKernel(FilterKernel, 2, null, globalWorkSize, null);
                oclCQ.EnqueueBarrier();
                CopyOCLBitmapToBitmap(openCLOutputImage, testImageOutput);              
                oclCQ.Finish();
            }
        }
        public static void BuildOpenCLSource(string source)
        {
            oclProgram = oclContext.CreateProgramWithSource(source);
            oclProgram.Build();
            FilterKernel = oclProgram.CreateKernel("FilterImage");
        }
        static unsafe void CopyOCLBitmapToBitmap(Mem oclBitmap, Bitmap bitmap)
        {            
            lock (bitmap)
            {
                BitmapData bd = null;
                try
                {
                    IntPtr[] origin = new IntPtr[3];
                    IntPtr[] region = new IntPtr[3];
                    Mem buffer;

                    bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
                    buffer = oclContext.CreateBuffer((MemFlags)((long)MemFlags.WRITE_ONLY | (long)MemFlags.USE_HOST_PTR), bd.Height * bd.Stride, bd.Scan0);
                    origin[0] = (IntPtr)0;
                    origin[1] = (IntPtr)0;
                    origin[2] = (IntPtr)0;
                    region[0] = (IntPtr)bd.Width;
                    region[1] = (IntPtr)bd.Height;
                    region[2] = (IntPtr)1;
                    oclCQ.EnqueueCopyImageToBuffer(oclBitmap, buffer, origin, region, IntPtr.Zero);
                    oclCQ.EnqueueBarrier();
                    IntPtr p = oclCQ.EnqueueMapBuffer(buffer, true, MapFlags.READ, IntPtr.Zero, (IntPtr)(bd.Height * bd.Stride));
                    oclCQ.EnqueueUnmapMemObject(buffer, p);
                    oclCQ.Finish();
                    buffer.Dispose();
                }
                finally
                {
                    if (bd != null)
                    {
                        bitmap.UnlockBits(bd);
                    }
                }
            }
        }
        public static void OpenCLContextNotifyCallback(string errInfo, byte[] privateInfo, IntPtr callbackValue, IntPtr userData)
        {
            CallBackEventList.Add(errInfo);          
        }
        public static void CreateContext(Platform platform, Device device)
        {
            if (platform != null)
            {
                IntPtr[] contextProperties = new IntPtr[]
            {
                (IntPtr)ContextProperties.PLATFORM, platform.PlatformID,
                IntPtr.Zero, IntPtr.Zero
            };

                Device[] devices = new Device[]
            {
                device
            };

                oclContext = platform.CreateContext(contextProperties, devices, oclContextNotify, IntPtr.Zero);
                oclCQ = oclContext.CreateCommandQueue(device, CommandQueueProperties.PROFILING_ENABLE);
            }
        }
        void progressPicturesBox_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
           
            using (Font newFont = new Font("Arial", 12f, FontStyle.Regular))
            {
                if (!scanningFiles)
                {
                    if (!I_AM_IDLE || !String.IsNullOrEmpty(save_folder_path))
                    {
                        if (workingThreads != null && workingThreads.listOfFiles != null && workingThreads.listOfFiles.Count > 0)
                        {
                            double procentCal = (workingThreads.progressPosition / (float)workingThreads.listOfFiles.Count);
                            float newWidth = (float)procentCal * progressPicturesBox.Width;
                           
                            using (SolidBrush greenBrush = new SolidBrush(mainBackgroundColor[1]))
                            {
                               
                                string procentTitle = String.Empty;
                                if (workingThreads.progressPosition != workingThreads.listOfFiles.Count)
                                {              
                                    procentCal = Math.Round(procentCal * 100, 1);
                                    procentTitle = procentCal.ToString(CultureInfo.InvariantCulture);
                                    if (procentCal >= 10 && procentTitle.Length == 2 || procentCal < 10 && procentTitle.Length == 1)
                                    {
                                        procentTitle += ".0";
                                    }                                  
                                    procentTitle += procent;
                                }
                                else
                                {
                                    procentTitle = getResourceString("doneText", myLanguage);
                                }
                                SizeF stringSize = e.Graphics.MeasureString(procentTitle, newFont);

                                float half = (progressPicturesBox.Width / 2 + stringSize.Width / 2);
                                if (half < newWidth)
                                {
                                    half = newWidth;
                                }
                                e.Graphics.Clip = new Region(new RectangleF(0, 0, half, progressPicturesBox.Height));
                                 e.Graphics.FillRectangle(greenBrush, new RectangleF(0, 0, newWidth, progressPicturesBox.Height));
                                using (SolidBrush whiteBrush = new SolidBrush(Color.White))
                                {
                                    e.Graphics.DrawString(procentTitle, newFont, whiteBrush, new PointF((progressPicturesBox.Width - stringSize.Width) / 2, (progressPicturesBox.Height - stringSize.Height) / 2));
                                    lastProgressUpdate = workingThreads.progressPosition;
                                }
                            }
                        }
                    }
                    else
                    {
                        SizeF stringSize = e.Graphics.MeasureString(getResourceString("readyText", myLanguage), newFont);
                        using (SolidBrush whiteBrush = new SolidBrush(Color.White))
                        {
                            float[] half = {(progressPicturesBox.Width - stringSize.Width) / 2, (progressPicturesBox.Height - stringSize.Height) / 2};
                            e.Graphics.Clip = new Region(new RectangleF(half[0], (progressPicturesBox.Height - stringSize.Height)/2, stringSize.Width, stringSize.Height));
                            e.Graphics.DrawString(getResourceString("readyText", myLanguage), newFont, whiteBrush, new PointF(half[0], half[1]));
                        }
                    }
                }
                else
                {
                    SizeF stringSize = e.Graphics.MeasureString(ImageResizerGPGPU.Properties.Resources.scanningText, newFont);
                    using (SolidBrush whiteBrush = new SolidBrush(Color.White))
                    {
                        float[] half = { (progressPicturesBox.Width - stringSize.Width) / 2, (progressPicturesBox.Height - stringSize.Height) / 2 };
                        e.Graphics.Clip = new Region(new RectangleF(half[0], (progressPicturesBox.Height - stringSize.Height) / 2, stringSize.Width, stringSize.Height));
                        e.Graphics.DrawString(ImageResizerGPGPU.Properties.Resources.scanningText, newFont, whiteBrush, new PointF(half[0], half[1]));
                    }
                }
            }
        }
        class NetworkController : IDisposable
        {
            /*
             * ORDERS
             * 0 - are you idle
             * 1 - yes I am idle
             * 2 - no I am not idle
             * 3 - how many cores are available?
             * 4 - this is how many cores are available
             * 5 - 5;index;size;StartCOMport;ip; GO!    
             */
            private int allRemoteCores = 0;
            static List<IPAddress> localIp = new List<IPAddress>();           
            MainForm mainRef;
            public void Dispose()
            {
                disposeExchangeList();
            }
            public void disposeExchangeList()
            {
                for (int i = ExchangeClassList.Count - 1; i >= 0; i--)
                {
                    for (int y = ExchangeClassList[i].Cores.Count - 1; y >= 0; y--)
                    {
                        ExchangeClassList[i].Cores[y].Dispose();
                    }
                }
                ExchangeClassList.Clear();
            }
            public void resetClass()
            {
                localIp.Clear();
                disposeExchangeList();
                allRemoteCores = 0;
            }
            public static string getLocalIps()
            {
                string ret = "";
                for (int o = 0; o < localIp.Count; o++)
                {
                    ret += localIp[o].ToString() + ((o+1 < localIp.Count) ? "," : "");
                }
                return ret;
            }
           public class ExchangeClass
            {
                public List<ClassCores> Cores = new List<ClassCores>();
                public void PAUSE()
                {
                    if (Cores.Count > 0)
                    {
                        Cores[0].sendDataToCore("6");                       
                    }
                }
                public void RESUME()
                {
                    if (Cores.Count > 0)
                    {
                        Cores[0].sendDataToCore("7" + width.ToString(CultureInfo.InvariantCulture) + ";" + height.ToString(CultureInfo.InvariantCulture) + ";" + q.ToString(CultureInfo.InvariantCulture));                        
                    }
                }
                public class ClassCores : IDisposable
                {
                    public IPAddress IP;
                    public int PORT = 8129;                  
                    private Socket mainTcpClientObject;                
                    private bool dataSend = false;
                    public int startPort = 8129;
                    Socket newClient = null;
                    public bool isMasterCore = false;
                    public WorkerBg myThread = null;
                    public int syncLoopNumber = -1;                   
                    private int timeOutSeconds = 10;
                    Thread myListeningThread = null;
                    public ClassCores(IPAddress IP, int PORT, bool addPort, bool isMasterCore)
                    {
                        this.IP = IP;
                        if (addPort)
                        {
                            this.PORT += PORT;
                        }
                        else
                        {
                            this.PORT = PORT;
                        }
                        this.isMasterCore = isMasterCore;
                        myListeningThread = new Thread(new ThreadStart(startListening));
                        myListeningThread.Priority = ThreadPriority.AboveNormal;
                        myListeningThread.Start();
                        //ThreadPool.QueueUserWorkItem(new WaitCallback(startListening));
                    }
                    public int getSyncLoop(int currentLoop)
                    {
                        if (syncLoopNumber == -1 || syncLoopNumber == currentLoop)
                        {
                            return currentLoop;
                        }
                        else
                        {
                            try
                            {
                                System.Threading.Interlocked.Add(ref workingThreads.progressPosition, (syncLoopNumber - currentLoop) - 1);
                                return syncLoopNumber-1;
                            }
                            finally
                            {
                                syncLoopNumber = -1;
                            }
                        }
                    }
                    public bool sendDataToCore(string dataToSend)
                    {
                        try
                        {
                            using (Socket udp = new Socket(IP.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
                            {
                                IAsyncResult result = udp.BeginConnect(IP, 8128, null, null);                               
                                for (int o = 0; o < timeOutSeconds * 2; o++)
                                {
                                    result.AsyncWaitHandle.WaitOne(500, true);
                                    if (udp.Connected)
                                    {
                                        byte[] basicData = Encoding.ASCII.GetBytes(dataToSend);
                                        udp.Send(basicData, 0, basicData.Length, SocketFlags.None);                                      
                                        return true;
                                    }
                                }
                                return false;
                            }
                        }
                        catch (SocketException)
                        {
                            return false;
                        }                       
                    }                    
                    bool startConnection()
                    {
                        if (!dataSend && MASTER && isMasterCore)
                        {
                            dataSend = sendDataToCore("5" + workingThreads.sizePerThread.ToString(CultureInfo.InvariantCulture) + ";" + startPort.ToString(CultureInfo.InvariantCulture) + ";" + getLocalIps() + ";" + width.ToString(CultureInfo.InvariantCulture) + ";" + height.ToString(CultureInfo.InvariantCulture) + ";" + q.ToString(CultureInfo.InvariantCulture));
                        }
                        try
                        {
                            mainTcpClientObject = new Socket(IP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);                        
                            IAsyncResult result = mainTcpClientObject.BeginConnect(IP, PORT, null, null);
                            for (int o = 0; o < timeOutSeconds*2; o++)
                            {
                                result.AsyncWaitHandle.WaitOne(500, true);
                                if (mainTcpClientObject.Connected)
                                {
                                    return true;
                                }
                            }
                            return false;
                        }
                        catch (SocketException)
                        {
                            return false;
                        }                       
                    }
                    protected virtual void Dispose(bool disposing)
                    {
                        if (disposing)
                        {                           
                            if (mainTcpClientObject != null)
                            {
                                mainTcpClientObject.Close();
                            }                            
                        }
                        Dispose();
                    }
                    public void Dispose()
                    {                        
                        if (!MASTER)
                        {
                            sendDataToCore("9" + PORT.ToString(CultureInfo.InvariantCulture));
                        }
                        myListeningThread.Abort();
                        if (tcpListeningObject != null)
                        {
                            tcpListeningObject.Close();
                        }
                        if (newClient != null)
                        {
                            newClient.Close();
                        }
                        GC.SuppressFinalize(this);
                    }
                   Socket tcpListeningObject = null;
                   public void startListening()
                   {
                       try
                       {
                           tcpListeningObject = new Socket(IP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                           tcpListeningObject.Bind(new IPEndPoint(((IP.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any), PORT));
                           tcpListeningObject.Listen(100);
                           while (true)
                           {
                               while (newClient != null)
                               {
                                   Thread.Sleep(1);                                   
                               }                              
                               try
                               {
                                   newClient = tcpListeningObject.Accept();
                               }
                               catch (SocketException s)
                               {
                                   if (s.SocketErrorCode == SocketError.Interrupted)
                                   {
                                       break;
                                   }
                               }
                               catch (ObjectDisposedException)
                               {
                                   break;
                               }
                           }
                       }
                       catch (SocketException)
                       { }
                       finally
                       {
                           if (tcpListeningObject != null)
                           {
                               tcpListeningObject.Close();
                           }
                       }                       
                   }
                    public MemoryStream StartRead()
                    {
                        MemoryStream memoryOriginal = null;
                        MemoryStream memoryTemp = null;
                        DateTime start = DateTime.Now;
                        try
                        {                      
                           while (newClient == null)
                            {
                                Thread.Sleep(10);
                                if (start.AddSeconds(5) < DateTime.Now)
                                {
                                    break;
                                }
                            }
                           if (newClient != null)
                           {
                               memoryTemp = new MemoryStream(1024000);
                               byte[] data = new byte[102400];
                               int readedData = 0;
                               while (newClient.Connected)
                               {
                                   readedData = newClient.Receive(data, 0, data.Length, SocketFlags.None);
                                   if (readedData != 0)
                                   {
                                       memoryTemp.Write(data, 0, readedData);
                                   }
                                   else
                                   {
                                       break;
                                   }
                               }
                               newClient.Close();
                               memoryOriginal = memoryTemp;
                               memoryTemp = null;
                           }                          
                        }
                        catch (SocketException)
                        {
                            memoryOriginal = null;
                        }
                        finally
                        {
                            if (memoryTemp != null)
                            {
                                memoryTemp.Dispose();
                                if (memoryOriginal != null)
                                {
                                    memoryOriginal.Dispose();
                                }
                            }
                            if (newClient != null && newClient.Connected)
                            {
                                newClient.Close();
                            }
                            newClient = null;
                        }
                        return memoryOriginal;
                    }
                    public unsafe void StartRead(ref Bitmap loadedImage)
                    {
                        int readedData = 0;                        
                        int wholeLength = 0;
                        int wholeReadedLength = 0;
                        Socket tcpClientObject = null;
                        DateTime start = DateTime.Now;
                        try
                        {
                            while (newClient == null)
                            {
                                Thread.Sleep(10);
                                if (start.AddSeconds(5) < DateTime.Now)
                                {
                                    break;
                                }
                            }
                            if (newClient != null)
                            {
                                tcpClientObject = newClient;
                                byte* data = null;
                                readedData = 0;
                                int dataLength = 102400;
                                byte[] temporaryData = new byte[dataLength];
                                BitmapData bitData = null;                                
                                try
                                {
                                    while (tcpClientObject.Connected)
                                    {
                                        if (wholeLength == 0)
                                        {
                                            byte[] getSize = new byte[sizeof(int) * 3];
                                            readedData = tcpClientObject.Receive(getSize, 0, getSize.Length, SocketFlags.None);
                                            wholeLength = BitConverter.ToInt32(getSize, 0);
                                            Size imageReportedSize = new Size(BitConverter.ToInt32(getSize, 4), BitConverter.ToInt32(getSize, 8));
                                            loadedImage = new Bitmap(imageReportedSize.Width, imageReportedSize.Height);
                                            bitData = loadedImage.LockBits(new Rectangle(Point.Empty, imageReportedSize), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                                            data = (byte*)bitData.Scan0.ToPointer();
                                        }
                                        else
                                        {
                                            readedData = tcpClientObject.Receive(temporaryData, 0, dataLength, SocketFlags.None);
                                            for (int o = 0; o < readedData; o++)
                                            {
                                                *data = temporaryData[o];
                                                data++;
                                            }
                                            wholeReadedLength += readedData;
                                        }
                                        if (readedData == 0)
                                        {
                                            break;
                                        }
                                    }
                                }
                                catch (SocketException)
                                {
                                }
                                if (loadedImage != null)
                                {
                                    loadedImage.UnlockBits(bitData);
                                    if (wholeLength != wholeReadedLength)
                                    {
                                        loadedImage = null;
                                    }
                                }
                            }
                        }
                        finally
                        {
                            if (tcpClientObject != null)
                            {
                                tcpClientObject.Close();
                            }
                            if (newClient != null && newClient.Connected)
                            {
                                newClient.Close();                               
                            }
                            newClient = null;
                        }                       
                    }
                    public bool StartWrite(byte[] data)
                    {                       
                        bool connectionSuccess = startConnection();
                        if (connectionSuccess)
                        {
                            try
                            {
                                int writeSize = 102400;
                                int allCount = data.Length / writeSize;
                                for (int u = 0; u < allCount; u++)
                                {
                                    mainTcpClientObject.Send(data, u * writeSize + ((allCount == u + 1) ? data.Length % writeSize : 0), writeSize, SocketFlags.None);
                                }                               
                            }
                            catch (SocketException)
                            {
                                connectionSuccess = false;
                            }
                            finally
                            {
                                if (mainTcpClientObject != null)
                                {
                                    mainTcpClientObject.Close();
                                }
                            }
                        }
                        return connectionSuccess;
                    }
                    public unsafe bool StartWrite(IntPtr data, int size, Size sizeOfImageSending)
                    {
                        bool writenGood = true;
                        byte* pointerToStart = (byte*)data.ToPointer();
                        startConnection();
                        int writeSize = 102400;
                        int allCount = size / writeSize;
                        int lengthOstanek = 0;
                        byte[] sendData = new byte[writeSize];
                        try
                        {
                            for (int u = 0; u < allCount; u++)
                            {
                                if (u == 0)
                                {
                                    byte[] allSizeBytes = new byte[sizeof(int) * 3];
                                    byte[] allSize = BitConverter.GetBytes(size);
                                    byte[] allSizeW = BitConverter.GetBytes(sizeOfImageSending.Width);
                                    byte[] allSizeH = BitConverter.GetBytes(sizeOfImageSending.Height);
                                    allSize.CopyTo(allSizeBytes, 0);
                                    allSizeW.CopyTo(allSizeBytes, sizeof(int));
                                    allSizeH.CopyTo(allSizeBytes, sizeof(int) * 2);
                                    mainTcpClientObject.Send(allSizeBytes, 0, allSizeBytes.Length, SocketFlags.None);
                                    lengthOstanek = size % writeSize;
                                    if (lengthOstanek != 0)
                                    {
                                        allCount++;
                                    }
                                    else
                                    {
                                        lengthOstanek = writeSize;
                                    }
                                }
                                int writeSizeCurrent = ((allCount != u + 1) ? writeSize : lengthOstanek);
                                for (int n = 0; n < writeSizeCurrent; n++)
                                {
                                    sendData[n] = *pointerToStart;
                                    pointerToStart++;
                                }
                                mainTcpClientObject.Send(sendData, 0, writeSizeCurrent, SocketFlags.None);
                            }
                            mainTcpClientObject.Close();
                        }
                        catch (SocketException)
                        {
                            writenGood = false;
                        }
                        return writenGood;
                    }
                }
            }        
            public List<ExchangeClass> ExchangeClassList = new List<ExchangeClass>();
            public ExchangeClass.ClassCores getExchangeClassByIndex(int index)
            {
                for (int o = 0; o < ExchangeClassList.Count; o++)
                {
                    for (int u = 0; u < ExchangeClassList[o].Cores.Count; u++)
                    {
                        if (index == 0)
                        {
                            return ExchangeClassList[o].Cores[u];
                        }
                        index--;
                    }
                }
                return null;
            }
            public ExchangeClass.ClassCores getExchangeClassByPort(int portNumber)
            {
                for (int o = 0; o < ExchangeClassList.Count; o++)
                {
                    for (int u = 0; u < ExchangeClassList[o].Cores.Count; u++)
                    {
                        if (ExchangeClassList[o].Cores[u].PORT == portNumber)
                        {
                            return ExchangeClassList[o].Cores[u];
                        }
                    }
                }
                return null;
            }
            public int getExchangeClassLength()
            {
                int fullLength = 0;
                for (int o = 0; o < ExchangeClassList.Count; o++)
                {                                          
                     fullLength += ExchangeClassList[o].Cores.Count;                    
                }
                return fullLength;
            }
            public NetworkController(bool listen, MainForm main)
            {
                mainRef = main;
                if (listen)
                {                   
                    ThreadPool.QueueUserWorkItem(new WaitCallback(startListening));                    
                }
            }
            public void resetNetwork()
            {
                ExchangeClassList.Clear();
                allRemoteCores = 0;
            }
            public void refreshPartners(object refrenceToCores)
            {               
                number_update num = new number_update(update_number);
                resetNetwork();
                if (!ImageResizerGPGPU.Properties.Settings.Default.workLocal)
                {
                    startCommunication();
                    if (ImageResizerGPGPU.Properties.Settings.Default.useOnlyNetworkPCs && allRemoteCores != 0)
                    {
                        workingThreads.numCores = allRemoteCores;
                    }
                    else
                    {
                        workingThreads.numCores += allRemoteCores;
                    }
                    workingThreads.NumCoresAll = allRemoteCores - 1;
                }
                if (workingThreads.numCores > workingThreads.listOfFiles.Count)
                {
                    int removeCores = workingThreads.numCores - workingThreads.listOfFiles.Count;
                    workingThreads.numCores -= removeCores;
                    workingThreads.NumCoresAll -= removeCores;
                }
                workingThreads.sizePerThread = workingThreads.listOfFiles.Count / workingThreads.numCores;
                mainRef.Invoke(num, false);
                workingThreads.initialize();
            }
            void startListening(object none)
            {        
               ThreadPool.QueueUserWorkItem(new WaitCallback(startListeningByProtocol), false);
               if (Socket.OSSupportsIPv6)
               {
                   ThreadPool.QueueUserWorkItem(new WaitCallback(startListeningByProtocol), true);
               }
            }
            private void startListeningByProtocol(object parameters)
            {
                bool protocolIpv6 = (bool)parameters;            
                AddressFamily family = ((protocolIpv6) ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork);               
                while (true)
                {
                    Socket reciveClient = null;
                    try
                    {
                        using (System.Net.Sockets.Socket udp = new System.Net.Sockets.Socket(family, SocketType.Stream, ProtocolType.Tcp))
                        {
                            // udp.Blocking = true;
                            udp.Bind(new IPEndPoint(((family == AddressFamily.InterNetwork) ? IPAddress.Any : IPAddress.IPv6Any), 8128));
                            udp.Listen(1);
                            reciveClient = udp.Accept();
                        }
                        byte[] data = new byte[20480];
                        while (true)
                        {
                            if (reciveClient.Connected)
                            {
                                int strLen = reciveClient.Receive(data, 0, data.Length, SocketFlags.None);
                                if (strLen != 0)
                                {
                                    ParseTcpMessages(data, reciveClient, strLen);
                                }
                                else
                                {
                                    reciveClient.Shutdown(SocketShutdown.Both);
                                    reciveClient.Close();
                                    break;
                                }
                            }
                            else
                            {
                                reciveClient.Close();
                                break;
                            }
                        }
                    }
                    catch (SocketException) { }
                }
            }
            private void startCommunication()
            {
                string[] Ips = scanForPartners();            
                int GoodClients=0;
                allRemoteCores = 0;
                for (int i = 0; i < Ips.Length; i++)
                {   
                    IPAddress IP = IPAddress.Parse(Ips[i]);
                    if (IPAddress.IsLoopback(IP))
                    {
                        continue;
                    }
                    using (Socket socket = new Socket(IP.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
                    {
                        socket.ReceiveTimeout = 50;
                        IAsyncResult result = socket.BeginConnect(IP, 8128, null, null);
                        result.AsyncWaitHandle.WaitOne(50, true);
                        if (!socket.Connected)
                        {
                            continue;
                        }
                        System.Net.Sockets.Socket stream = socket;
                        int step = 0;
                        System.Int16 len = 1;
                        string addData = string.Empty;
                        for (;;)
                        {
                            byte[] dataReply = new byte[len];
                            byte[] data = Encoding.ASCII.GetBytes((step + addData).ToString());
                            try
                            {
                                stream.Send(data, data.Length, SocketFlags.None);
                                stream.Receive(dataReply);
                            }
                            catch (SocketException) 
                            {
                                break;
                            }
                            string reply = Encoding.ASCII.GetString(dataReply);
                            if (step == 0)
                            {
                                if (reply == "1")
                                {
                                    step = 3;
                                    len = 20;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else if (step == 3)
                            {
                                if (reply[0] == '4')
                                {
                                    int tmpCores = Convert.ToInt32(reply.Substring(1, reply.Length - 1), CultureInfo.InvariantCulture);
                                    ExchangeClassList.Add(new ExchangeClass());
                                    int[] index = { ExchangeClassList.Count - 1, 0 };
                                    int startPort = 0;
                                    for (int p = tmpCores; p > 0; p--)
                                    {
                                        ExchangeClassList[index[0]].Cores.Add(new ExchangeClass.ClassCores(IP, GoodClients, true, (p == tmpCores)));
                                        index[1] = ExchangeClassList[index[0]].Cores.Count - 1;                                   
                                        if (p == tmpCores)
                                        {
                                            startPort = ExchangeClassList[index[0]].Cores[index[1]].PORT;
                                        }
                                        ExchangeClassList[index[0]].Cores[index[1]].startPort = startPort;
                                        GoodClients++;
                                        allRemoteCores++;
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            static void SendResponseMessage(string SendData, System.Net.Sockets.Socket stream)
            {
                byte[] data = ASCIIEncoding.ASCII.GetBytes(SendData);
                stream.Send(data, 0, data.Length, SocketFlags.None);
            }
            static void SendResponseMessage(string SendData, IPAddress IP)
            {
                try
                {
                    using (Socket udp = new Socket(IP.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
                    {
                        udp.Connect(new IPEndPoint(IP, 8128));
                        byte[] basicData = Encoding.ASCII.GetBytes(SendData);
                        udp.Send(basicData, 0, basicData.Length, SocketFlags.None);                      
                    }
                }
                catch (SocketException)
                {}    
            }
           static string getValidMaster(string ipList)
            {
                string[] recivedIps = ipList.Split(',');
                string[] localAddresses = scanForPartners();
                for(int i=0; i <localAddresses.Length; i++)
                {
                    for(int o=0; o < recivedIps.Length; o++)
                    {
                        if(recivedIps[o] == localAddresses[i])
                        {
                            return recivedIps[o];
                        }
                    }
                }
                if(recivedIps.Length > 0)
                {
                    return recivedIps[0];
                }
                else
                {
                    return "";
                }
            }
            void ParseTcpMessages(byte[] data, System.Net.Sockets.Socket stream, int strLen)
            {
                int OrderType = Convert.ToInt32(Encoding.ASCII.GetString(new byte[] { data[0] }), CultureInfo.InvariantCulture);
                if (OrderType == 0)
                {
                    if (I_AM_IDLE && ImageResizerGPGPU.Properties.Settings.Default.doUseMyPcDistributed)
                    {                       
                        SendResponseMessage("1", stream);
                    }
                    else
                    {
                        SendResponseMessage("0", stream);
                        stream.Close();
                    }
                }
                else if (OrderType == 1)
                {
                    SendResponseMessage("3", stream);
                }
                else if (OrderType == 2)
                {
                    stream.Close();
                }
                else if (OrderType == 3)
                {
                    int cores = Environment.ProcessorCount * CORE_SCALL_FACTORS.CPU_SLAVE + CUDA_OBJECT.CUDA_CORES * CORE_SCALL_FACTORS.GPU_SLAVE;
                    SendResponseMessage("4" + cores.ToString(CultureInfo.InvariantCulture), stream);
                }
                else if (OrderType == 5)
                {                   
                    MASTER = false;
                    I_AM_IDLE = false;
                    voidDelegate voidPointer = new voidDelegate(mainRef.BeSlave);
                    mainRef.Invoke(voidPointer);                   
                    //  5 size; StartCOMport; ip; 
                    one_image = false;
                    string[] strData = Encoding.ASCII.GetString(data, 0, strLen).Split(';');
                    int sizePerThread = Convert.ToInt32(strData[0].Substring(1, strData[0].Length - 1), CultureInfo.InvariantCulture);
                    int startPort = Convert.ToInt32(strData[1], CultureInfo.InvariantCulture);
                    ExchangeClassList.Add(new ExchangeClass());
                    IPAddress IP = IPAddress.Parse(getValidMaster(strData[2]));
                    setWidthHeightDelegate widthHeightPointer = new setWidthHeightDelegate(mainRef.SetWidthHeight);
                    mainRef.Invoke(widthHeightPointer, strData[3], strData[4], Convert.ToInt32(strData[5], CultureInfo.InvariantCulture));                   
                    int cores = Environment.ProcessorCount * CORE_SCALL_FACTORS.CPU_SLAVE + CUDA_OBJECT.CUDA_CORES * CORE_SCALL_FACTORS.GPU_SLAVE;
                    bool errorFree = true;
                    for (int k = cores; k > 0; k--)
                    {
                        if (ExchangeClassList.Count > 0)
                        {
                            ExchangeClassList[0].Cores.Add(new ExchangeClass.ClassCores(IP, startPort, false, (k == cores)));
                            startPort++;
                        }
                        else
                        {
                            errorFree = false;
                            break;
                        }
                    }
                    if (errorFree)
                    {
                        stream.Close();
                        workingThreads = new ListOfBgWorkers(mainRef, null);
                        workingThreads.sizePerThread = sizePerThread;
                        for (int i = 0; i < sizePerThread * cores; i++)
                        {
                            workingThreads.listOfFiles.Add(new ListFiles.FilePathAndCodec(1, string.Empty));
                        }
                        workingThreads.initialize();
                    }
                    
                }
                else if (OrderType == 6)
                {
                    THREADS_ARE_PAUSED = true;
                }
                else if (OrderType == 7)
                {
                    string[] recivedData = Encoding.ASCII.GetString(data, 1, strLen - 1).Split(';');
                    int newWidth = Convert.ToInt32(recivedData[0], CultureInfo.InvariantCulture);
                    int newHeight = Convert.ToInt32(recivedData[1], CultureInfo.InvariantCulture);
                    Int64 newQuality = Convert.ToInt64(recivedData[2], CultureInfo.InvariantCulture);
                    bool changed = false;
                    if (newHeight != height)
                    {
                        height = newHeight;
                        changed = true;
                    }
                    if (newWidth != width)
                    {
                        width = newWidth;
                        changed = true;
                    }
                    if (q != newQuality)
                    {
                        q = newQuality;
                        changed = true;
                    }
                    if (changed)
                    {
                        setWidthHeightDelegate widthHeightPointer = new setWidthHeightDelegate(mainRef.SetWidthHeight);
                        mainRef.Invoke(widthHeightPointer, width.ToString(CultureInfo.InvariantCulture), height.ToString(CultureInfo.InvariantCulture), (int)q); 
                    }
                    THREADS_ARE_PAUSED = false;
                }
                else if (OrderType == 8)
                {
                    string[] recivedData = Encoding.ASCII.GetString(data, 1, strLen - 1).Split(';');
                    if (recivedData[0] == "MASTER?")
                    {
                        int portNumber = Convert.ToInt32(recivedData[1], CultureInfo.InvariantCulture);
                        NetworkController.ExchangeClass.ClassCores coreToSync = NetworkControlerObject.getExchangeClassByPort(portNumber);
                        if (coreToSync == null)
                        {
                            SendResponseMessage("9" + recivedData[1], ((IPEndPoint)stream.RemoteEndPoint).Address); // don't need you anymore
                        }
                    }
                    else
                    {
                        int portNumber = Convert.ToInt32(recivedData[0], CultureInfo.InvariantCulture);
                        int loopNumber = Convert.ToInt32(recivedData[1], CultureInfo.InvariantCulture);
                        if (!MASTER)
                        {
                            NetworkController.ExchangeClass.ClassCores coreToSync = NetworkControlerObject.getExchangeClassByPort(portNumber);
                            if (coreToSync != null)
                            {
                                coreToSync.syncLoopNumber = loopNumber;
                            }
                        }
                        else
                        {
                            SendResponseMessage("9" + recivedData[0], ((IPEndPoint)stream.RemoteEndPoint).Address); // disconnect port
                        }
                    }
                }
                else if (OrderType == 9)
                {
                    string recivedData = Encoding.ASCII.GetString(data, 1, strLen - 1);
                    int portNumber = Convert.ToInt32(recivedData, CultureInfo.InvariantCulture);
                    NetworkController.ExchangeClass.ClassCores coreToSync = NetworkControlerObject.getExchangeClassByPort(portNumber);
                    if (coreToSync != null)
                    {
                        if (MASTER)
                        {
                            coreToSync.myThread.disconnectNetworkNext();
                        }
                        else
                        {
                            voidDelegate voidPointer = new voidDelegate(mainRef.noMoreSlave);
                            mainRef.Invoke(voidPointer);
                        }
                    }
                }
            }   
            public static void MyAddress()
            {
                foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
                {
                    if (ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
                    {
                        foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
                        {
                            if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork || Socket.OSSupportsIPv6 && ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                            {                        
                                localIp.Add(ip.Address);
                            }
                        }                      
                    }
                }                
            }
            static bool containsIp(IPAddress ip)
            {
                for (int i = 0; i < localIp.Count; i++)
                {
                    if (ip == localIp[i])
                    {
                        return true;
                    }
                }
                return false;
            }
            static int scanIpRange = 100;
            static IPAddress[] determineLocalAreaRangeStartIp()
            {
                List<IPAddress> uniqueAreas = new List<IPAddress>();
                for (int i = 0; i < localIp.Count; i++)
                {
                    uniqueAreas.Add(addToIpAddress(scanIpRange*-1, localIp[i]));                 
                }
                return uniqueAreas.ToArray();
            }
            static IPAddress addToIpAddress(int addThisMuch, IPAddress ipAdressToChange)
            {
                string newIpAddressToReturn = string.Empty;
                byte[] addressInBytes = ipAdressToChange.GetAddressBytes();
                byte[] addressBytes = null;
                if (addressInBytes.Length == 4)
                {
                    UInt32 ipIntegerValue = BitConverter.ToUInt32(addressInBytes.Reverse().ToArray(), 0);
                    Int64 checkValidity = (Int64)ipIntegerValue + addThisMuch;
                    if (checkValidity < UInt32.MinValue)
                    {
                        addThisMuch -= (int)checkValidity;
                    }
                    else if (checkValidity > UInt32.MaxValue)
                    {
                        addThisMuch -= (int)(checkValidity - UInt32.MaxValue);
                    }
                    for (int p = 0; p < Math.Abs(addThisMuch); p++)
                    {
                        if (addThisMuch < 0)
                        {
                            ipIntegerValue--;
                        }
                        else
                        {
                            ipIntegerValue++;
                        }
                    }            
                    addressBytes = BitConverter.GetBytes(ipIntegerValue);
                    addressInBytes = addressBytes.Reverse().ToArray();
                    for (int o = addressBytes.Length - 1; o > -1; o--)
                    {
                        newIpAddressToReturn += ((o != addressBytes.Length - 1) ? "." : string.Empty) + Convert.ToString((int)addressBytes[o], CultureInfo.InvariantCulture);
                    }
                }
                else if (addressInBytes.Length == 16)
                {                   
                    System.UInt64[] addressValues = new System.UInt64[2];                   
                    for (int i = 2; i > 0; i--)
                    {
                        byte[] reversedBytes = new byte[]{addressInBytes[i*8-1], 
                                                addressInBytes[i*8-2], 
                                                addressInBytes[i*8-3], 
                                                addressInBytes[i*8-4], 
                                                addressInBytes[i*8-5], 
                                                addressInBytes[i*8-6], 
                                                addressInBytes[i*8-7], 
                                                addressInBytes[i*8-8]};
                        addressValues[2-i] = BitConverter.ToUInt64(reversedBytes, 0);                      
                    }
                    UInt64 addThisMuchAbsolute = Convert.ToUInt64(Math.Abs(addThisMuch));
                    if (addThisMuch < 0)
                    {
                        if (addressValues[0] > addThisMuchAbsolute)
                        {
                            addressValues[0] -= addThisMuchAbsolute;
                        }
                        else
                        {
                            UInt64 removeFromSecondPart = addThisMuchAbsolute - addressValues[0];
                            addressValues[0] = 0;
                            if (addressValues[1] > removeFromSecondPart)
                            {
                                addressValues[1] -= removeFromSecondPart;
                            }
                            else
                            {
                                addressValues[1] = 0;
                            }
                        }
                    }
                    else
                    {
                        UInt64 stillTillTheEnd = UInt64.MaxValue - addressValues[0];
                        if (stillTillTheEnd > addThisMuchAbsolute)
                        {
                            addressValues[0] += addThisMuchAbsolute;
                        }
                        else
                        {
                            UInt64 removeFromSecondPart = addThisMuchAbsolute - stillTillTheEnd;
                            addressValues[0] = UInt64.MaxValue;
                            stillTillTheEnd = UInt64.MaxValue - addressValues[1];
                            if (stillTillTheEnd > removeFromSecondPart)
                            {
                                addressValues[1] += removeFromSecondPart;
                            }
                            else
                            {
                                addressValues[1] = UInt64.MaxValue;
                            }
                        }
                    }

                    BitConverter.GetBytes(addressValues[0]).Reverse().ToArray().CopyTo(addressInBytes, 8);
                    BitConverter.GetBytes(addressValues[1]).Reverse().ToArray().CopyTo(addressInBytes, 0);
                    for (int x = 0; x < 8; x++)
                    {
                        newIpAddressToReturn += ((x != 0) ? ":" : string.Empty) + String.Format(CultureInfo.InvariantCulture,"{0:X}", BitConverter.ToUInt16(new byte[] { addressInBytes[x*2 + 1], addressInBytes[x*2] }, 0));
                    }                   
                }              
               
                return IPAddress.Parse(newIpAddressToReturn);
            }
            static List<string> ResponseString = new List<string>();
            static long completedScans = 0;
            static object ResposneStringLock = new object();
            static string[] scanForPartners()
            {                
              //  IntPtr completedScans = Marshal.AllocHGlobal(sizeof(int));
                MyAddress();
                IPAddress[] uniqueLocalAreas = determineLocalAreaRangeStartIp();
                Ping[] getResponse = new Ping[uniqueLocalAreas.Length * scanIpRange * 2];                
              //  Marshal.WriteInt32(completedScans, 0);
                ResponseString.Clear();
                for (int x = 0; x < uniqueLocalAreas.Length; x++)
                {
                    IPAddress ipTmp = uniqueLocalAreas[x];
                    for (int u = 0; u < scanIpRange * 2; u++)
                    {                        
                        int pingIndex = x * scanIpRange * 2 + u;
                        getResponse[pingIndex] = new Ping();
                        getResponse[pingIndex].PingCompleted += getResponse_PingCompleted;
                        if (!containsIp(ipTmp) && !ResponseString.Contains(ipTmp.ToString()))
                        {                            
                            getResponse[pingIndex].SendAsync(ipTmp, 1500, null);                           
                        }                        
                        ipTmp = addToIpAddress(1, ipTmp);
                    }
                }
                while (System.Threading.Interlocked.Read(ref completedScans) < scanIpRange * 2)
                {
                    Thread.Sleep(10);
                }
                for (int f = 0; f < 20; f++)
                {
                    if (getResponse[f] != null)
                    {
                        getResponse[f].Dispose();
                    }
                }
                return ResponseString.ToArray();
            }

            static void getResponse_PingCompleted(object sender, PingCompletedEventArgs e)
            {
                //IntPtr completedScans = (IntPtr)e.UserState;                
                PingReply reply = e.Reply;
                if (reply.Status == IPStatus.Success)
                {
                    long tmpLocked = 0;
                    try
                    {
                        System.Threading.Interlocked.Increment(ref tmpLocked);
                        Monitor.Enter(ResposneStringLock);
                        {
                            ResponseString.Add(e.Reply.Address.ToString());
                           
                        }
                        System.Threading.Interlocked.Decrement(ref tmpLocked);
                        Monitor.Exit(ResposneStringLock);
                    }
                    finally
                    {
                        if (tmpLocked == 1)
                        {
                            Monitor.Exit(ResposneStringLock);
                        }
                    }
                }
                System.Threading.Interlocked.Increment(ref completedScans);
              /*  int currentScanState = Marshal.ReadInt32(completedScans)+1;
                Marshal.WriteInt32(completedScans, currentScanState);*/
                ((Ping)sender).Dispose();
            }
        }
        void EngineChange()
        {
            if (!I_AM_IDLE && workingThreads != null)
            {
                if (GpuEnabledOnSystem)
                {
                    if (CPUPriorityCheckBox.Checked && GPUPriorityCheckBox.Checked)
                    {
                        int limit = (workingThreads.backWorkers.Count - 1) / 2;
                        if (limit < 1)
                        {
                            limit = 1;
                        }
                        for (int i = 0; i < workingThreads.backWorkers.Count; i++)
                        {
                            if (i > limit)
                            {
                                workingThreads.backWorkers[i].USE_GPU = false;
                            }
                            else
                            {
                                workingThreads.backWorkers[i].USE_GPU = true;
                            }
                        }
                    }
                    else if (GPUPriorityCheckBox.Checked)
                    {
                        for (int i = 0; i < workingThreads.backWorkers.Count; i++)
                        {
                            workingThreads.backWorkers[i].USE_GPU = true;
                        }
                    }
                    else
                    {
                        for (int i = 0; i < workingThreads.backWorkers.Count; i++)
                        {
                            workingThreads.backWorkers[i].USE_GPU = false;
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < workingThreads.backWorkers.Count; i++)
                    {
                        workingThreads.backWorkers[i].USE_GPU = false;
                    }
                }
            }
        }
        class ListOfBgWorkers : IDisposable
        {
            public List<WorkerBg> backWorkers = new List<WorkerBg>();
            public ListFiles Data = null;
            public ImageResizerGPGPU.MainForm.ListFiles.ListFilePathAndCodec listOfFiles = new ImageResizerGPGPU.MainForm.ListFiles.ListFilePathAndCodec();       
            public int progressPosition = 0;
            public MainForm refToParent = null;
            public int numCores = 1;
            public int NumCoresAll = -1;
            public int numberOfGpuCores = 0;
            public int numberOfCpuCores = 0;
            public int sizePerThread = 1;
            public ListOfBgWorkers(MainForm refThis, List<string> userOnlyThereDirs)
            {
                refToParent = refThis;
                if (!one_image || !MASTER)
                {
                    if (MASTER)
                    {
                        numberOfCpuCores = Environment.ProcessorCount * CORE_SCALL_FACTORS.CPU_MASTER;
                        numberOfGpuCores = CUDA_OBJECT.CUDA_CORES * CORE_SCALL_FACTORS.GPU_MASTER;
                        numCores = numberOfCpuCores + numberOfGpuCores;
                        Data = getFiles(path, userOnlyThereDirs, refToParent);
                        if (Data != null)
                        {
                            listOfFiles = (ImageResizerGPGPU.MainForm.ListFiles.ListFilePathAndCodec)Data.getRawFiles(true);
                            if (listOfFiles.Count > 0)
                            {
                                if (!ImageResizerGPGPU.Properties.Settings.Default.ignoreSubFolders)
                                {
                                    Data.createDirectories(save_folder_path);
                                }
                            }
                            else
                            {
                               MainForm.Instance().WorkerComplete();
                            }
                        }              
                    }
                    else
                    {
                        numberOfCpuCores = Environment.ProcessorCount * CORE_SCALL_FACTORS.CPU_SLAVE;
                        numberOfGpuCores = CUDA_OBJECT.CUDA_CORES * CORE_SCALL_FACTORS.GPU_SLAVE;
                        numCores = numberOfCpuCores + numberOfGpuCores;
                        NumCoresAll = NetworkControlerObject.getExchangeClassLength() - 1;
                    }         
                }
                else if (one_image)
                {
                    listOfFiles.Add(new ListFiles.FilePathAndCodec(GetEncoder(Path.GetExtension(save_folder_path)), string.Empty));
                }
            }
            public void initialize()
            {
                if (initialized)
                {
                    number_update num = new number_update(update_number);
                    MainForm.Instance().Invoke(num, false);
                }
                for (int i = 0; i < numCores && !I_AM_IDLE; i++)
                {                    
                    bool GPU_CORE = (numberOfGpuCores > 0 && (NumCoresAll < 0 && MASTER || NumCoresAll > -1 && !MASTER));
                    if (MASTER)
                    {                       
                        bool oneFilePerCore = (sizePerThread == 1 && listOfFiles.Count % numCores != 0);
                        if (!one_image && listOfFiles.Count > 1 && (sizePerThread > 1 && (listOfFiles.Count % sizePerThread != 0 || listOfFiles.Count % numCores != 0) ||
                            oneFilePerCore) && i + 1 == numCores)
                        {
                            backWorkers.Add(new WorkerBg(i * sizePerThread, (i + 1) * sizePerThread + listOfFiles.Count % numCores, GPU_CORE, NumCoresAll));                            
                        }
                        else
                        {
                            backWorkers.Add(new WorkerBg(i * sizePerThread, (i + 1) * sizePerThread, GPU_CORE, NumCoresAll));
                        }
                    }
                    else
                    {
                        backWorkers.Add(new WorkerBg(0, sizePerThread, GPU_CORE, NumCoresAll));
                    }                    
                    NumCoresAll--;
                    if (GPU_CORE)
                    {
                        numberOfGpuCores--;
                    }                    
                    backWorkers[i].WorkerSupportsCancellation = true;
                    backWorkers[i].DoWork += new DoWorkEventHandler(MainForm.Instance().back_DoWork);
                    backWorkers[i].RunWorkerCompleted += new RunWorkerCompletedEventHandler(MainForm.Instance().back_RunWorkerCompleted);
                    backWorkers[i].RunWorkerAsync();               
                }
                if (MASTER && !I_AM_IDLE)
                {
                    voidDelegate voidPointer = new voidDelegate(MainForm.Instance().showStartPauseButton);
                    refToParent.Invoke(voidPointer);
                }
            }
            protected virtual void Dispose(bool disposing)
            {
                if (disposing)
                {
                    for (int i = 0; i < backWorkers.Count - 1; i++)
                    {
                        backWorkers[i].CancelAsync();
                    }
                    backWorkers.Clear();
                }
            }
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
            public bool checkFinish()
            {
                for (int i = 0; i < backWorkers.Count; i++)
                {
                    if (backWorkers[i].IsBusy)
                    {
                        return false;
                    }
                }
                return true;
            }
        }
        public static bool CheckForValidPath(string path)
        {
            string normalizedPath = path.Replace("\\", "/");
            if (normalizedPath.Length < 260)
            {
                string name = Path.GetFileName(path);
                if (path.Length - name.Length < 248 || string.IsNullOrEmpty(name))
                {
                    return true;
                }
            }
            return false;
        }
        class WorkerBg : BackgroundWorker
        {
            private int workerStartIndex = 0;
            private int workerSize = 0;
            public bool USE_GPU = false;
            public int NETWORK_INDEX = -1;
            public NetworkController.ExchangeClass.ClassCores myCore = null;
            public bool disconnectNetwork = false;
            public WorkerBg(int index, int size, bool cuda, int network)
            {
                USE_GPU = cuda;
                setOrGetStartIndex = index;
                setOrGetSize = size;
                NETWORK_INDEX = network;               
            }
            public bool isWorkerNetwork
            {
                get
                {
                  return (NETWORK_INDEX > -1);
                }
            }
            public void isWorkerNetworkNoMore()
            {
                 NETWORK_INDEX = -1;
            }
            public void disconnectNetworkNext()
            {
                disconnectNetwork = true;
            }
            public int setOrGetStartIndex
            {
                set
                {
                    workerStartIndex = value;
                }
                get
                {
                    return workerStartIndex;
                }
            }
            public int setOrGetSize
            {
                set
                {
                    workerSize = value;
                }
                get
                {
                    return workerSize;
                }
            }
        }
        delegate void voidDelegate();
        void backWorkerFinished()
        {
            if (!MASTER)
            {
                noMoreSlave();
            }
            MainForm.Instance().stopAll();
        }        
      void back_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            WorkerComplete();
        }
      void WorkerComplete()
      {
          if (workingThreads == null || workingThreads.checkFinish())
          {
              if (!DISPOSED)
              {
                  try
                  {
                      voidDelegate finish = new voidDelegate(backWorkerFinished);
                      MainForm.Instance().Invoke(finish);
                  }
                  catch (InvalidOperationException) { }
              }
          }    
      }
      static System.Threading.Timer checkProgress = null;
      static void update_number(bool advancePosition)
      {
          if (checkProgress == null && advancePosition)
          {
              checkProgress = new System.Threading.Timer(new TimerCallback(RefreshProgress), null, 40, 40);
          }
          else if (!advancePosition)
          {
              MainForm.Instance().progressPicturesBox.Invalidate();
          }
      }
      static void RefreshProgress(object timer)
      {
          if (I_AM_IDLE)
          {
              if (checkProgress != null)
              {
                  checkProgress.Dispose();
                  checkProgress = null;
              }
              lastProgressUpdate = 0;
          }
          else if(MainForm.Instance().WindowState != FormWindowState.Minimized && lastProgressUpdate != workingThreads.progressPosition)
          {
              workingThreads.refToParent.progressPicturesBox.Invalidate(false);
          }
      }
        delegate void setWidthHeightDelegate(string width, string height, Int32 qualityLevel);
        public void SetWidthHeight(string widthValue, string heightValue, Int32 qualityLevel)
        {
            qualityTrackBar.Value = qualityLevel;
            textBoxImageWidth.Text = widthValue;
            textBoxImageHeight.Text = heightValue;
        }
        public enum SortTypes : int
        {
            SortByDay = 0,
            SortByWeek = 1,
            SortByMonth = 2,
            SortByYear = 3
        }
        class ListData
        {
            public ListData(string rt, string[] fl)
            {
                root = rt;
                files = fl;
                this.sortPath = new string[fl.Length];
            }
           public string root = "";
           public string[] files = null;
           public string[] sortPath = null;
        }
        class ListFiles : List<ListData>
        {
           public System.Text.RegularExpressions.Regex regexObject = new System.Text.RegularExpressions.Regex(@":|/");
           public  string old_root = "";        
           public ListFiles(string old_r)
           {               
               if (string.IsNullOrEmpty(old_r))
               {                   
                   old_root = regexObject.Replace(old_r, string.Empty);
               }
               old_root = old_r;
           }
            public class FilePathAndCodec
            {
                public int codecIndex;
                public string filePath;
                public string sortPath;
                public string fileName;
                public string root;
                public int uniqueIndex;
                public FilePathAndCodec(int index, string fileName, string sortPath = "", string root = "", string fileNameOnly = "", int uniqueIndex = 0)
                {
                    codecIndex = index;
                    filePath = fileName;
                    this.sortPath = sortPath;
                    this.fileName = fileNameOnly;
                    this.root = root;
                    this.uniqueIndex = uniqueIndex;
                }
            }
            public class ListFilePathAndCodec : List<FilePathAndCodec>
            {
                public int NameUniqueIndex(string name)
                {
                    for (int i = this.Count-1; i >= 0; i--)
                    {
                        if (name.Equals(this[i].fileName))
                        {
                            return this[i].uniqueIndex + 1;
                        }
                    }
                    return 0;
                }
            }
            private int getWeek(DateTime _dateTime)
            {
                DateTime _monthDate = new DateTime(_dateTime.Year, _dateTime.Month, 1);
                int yearDay =_monthDate.DayOfYear;
                int dayOfWeek = (int)_dateTime.DayOfWeek;
                return (int)Math.Floor((yearDay - dayOfWeek + 10d) / 7);
            }
            public object getRawFiles(bool listCodecs)
            {
                List<string> final = new List<string>();
                ListFilePathAndCodec listAllInfo = new ListFilePathAndCodec();
                for (int x = 0; x < this.Count; x++)
                {
                    for (int y = 0; y < this[x].files.Length; y++)
                    {
                        string ext = Path.GetExtension(this[x].files[y]).ToUpperInvariant();
                        if ((ext == ".JPG" || ext == ".JPEG" || ext == ".BMP" || ext == ".PNG" || ext == ".GIF" || ext == ".TIFF") && this[x].files[y][0] != '.')
                        {
                            string middleSortingPath = string.Empty;
                            if (MainForm._sortSettings.scanFileInfo)
                            {
                                FileInfo getFileInfo = new FileInfo(path + this[x].root + Path.DirectorySeparatorChar + this[x].files[y]);
                                if (MainForm._sortSettings.sortByYear)
                                {
                                    middleSortingPath = getFileInfo.CreationTime.Year.ToString() + Path.DirectorySeparatorChar; 
                                }
                                if (MainForm._sortSettings.sortByMonth)
                                {
                                    middleSortingPath += getFileInfo.CreationTime.Month.ToString() + Path.DirectorySeparatorChar;
                                }
                                if (MainForm._sortSettings.sortByWeek)
                                {
                                    middleSortingPath += "W" + getWeek(getFileInfo.CreationTime).ToString() + Path.DirectorySeparatorChar;
                                }
                                if (MainForm._sortSettings.sortByDay)
                                {
                                    middleSortingPath += getFileInfo.CreationTime.Day.ToString() + Path.DirectorySeparatorChar;
                                }
                                middleSortingPath = middleSortingPath.Remove(middleSortingPath.Length - 1, 1);
                                this[x].sortPath[y] = middleSortingPath;
                            }
                            string partName = this[x].root + Path.DirectorySeparatorChar.ToString() + this[x].files[y];
                            if (!listCodecs)
                            {
                                final.Add(partName);
                            }
                            else
                            {
                                string sortPath = ((this[x].sortPath[y] != null) ? Path.DirectorySeparatorChar + this[x].sortPath[y] : string.Empty);
                                string old_root_clean = regexObject.Replace(old_root, string.Empty);
                                string fileRootClean = regexObject.Replace(this[x].root, string.Empty);
                                string dirEnding = (old_root_clean + fileRootClean + sortPath);
                                string dirToCreate = save_folder_path + ((!dirEnding.StartsWith(Path.DirectorySeparatorChar.ToString())) ? Path.DirectorySeparatorChar.ToString() : string.Empty) + dirEnding + Path.DirectorySeparatorChar.ToString();
                                bool dirValid = CheckForValidPath(dirToCreate);
                                bool addToIndex = dirValid || ImageResizerGPGPU.Properties.Settings.Default.ignoreSubFolders;
                                if (addToIndex)
                                {
                                    listAllInfo.Add(new FilePathAndCodec(GetEncoder(ext), partName, middleSortingPath, this[x].root, this[x].files[y], listAllInfo.NameUniqueIndex(this[x].files[y])));
                                }
                              
                            }
                        }                        
                    }
                }
                if (!listCodecs)
                {
                    return final.ToArray();
                }
                else
                {
                    return listAllInfo;
                }
            }
           public void createDirectories(string root)
            {
                for (int x = 0; x < this.Count && !I_AM_IDLE; x++)
                {
                    for (int i = 0; i < this[x].sortPath.Length; i++)
                    {
                        if (this[x].files.Length > 0)
                        {
                            string sortPath = ((this[x].sortPath[i] != null) ? Path.DirectorySeparatorChar + this[x].sortPath[i] : string.Empty);
                            string old_root_clean = regexObject.Replace(old_root, string.Empty);
                            string fileRootClean = regexObject.Replace(this[x].root, string.Empty);
                            string dirToCreate = root + ((!ImageResizerGPGPU.Properties.Settings.Default.ignoreSubFolders) ? Path.DirectorySeparatorChar + old_root_clean + fileRootClean : string.Empty) + sortPath + Path.DirectorySeparatorChar.ToString();
                            if (CheckForValidPath(dirToCreate) && !Directory.Exists(dirToCreate))
                            {
                                Directory.CreateDirectory(dirToCreate);
                            }
                        }
                    }
                }               
            }
            public bool CompareListDirectories(ListFiles OtherFiles)
            {
                string[] Dir_0 = (string[])OtherFiles.getRawFiles(false);
                string[] DirThis = (string[])this.getRawFiles(false);
                if (Dir_0.Length == DirThis.Length)
                {
                    for (int i = 0; i < DirThis.Length; i++)
                    {
                        if (DirThis[i] != Dir_0[i])
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        static ListFiles getFiles(string path, List<string> useOnlyTheseDirs, MainForm mainRef)
        {
            voidDelegate voidPointer = new voidDelegate(mainRef.progressPicturesBox.Refresh);
            scanningFiles = true;
            mainRef.Invoke(voidPointer);
            string[] spliting = path.Split('\\');
            string root_folder = ((!checkIfItIsDisk(path)) ? spliting[spliting.Length - 1] : path);
            ListFiles listFinal = new ListFiles(root_folder);
            string[] data_fill = { path };                     
            List<string[]> dirList = new List<string[]>();
            dirList.Add(data_fill);
            try
            {
                for (int i = 0; ; i++)
                {
                    List<string> direktoriji = new List<string>();
                    for (int u = 0; u < dirList[i].Length; u++)
                    {
                        try
                        {
                            listFinal.Add(new ListData(dirList[i][u], Directory.GetFiles(dirList[i][u])));
                            for (int e = 0; e < listFinal[listFinal.Count - 1].files.Length; e++)
                            {
                                if (i == 0 && useOnlyTheseDirs != null)
                                {
                                    int indexInCollection = -1;
                                    for (int b = 0; b < useOnlyTheseDirs.Count; b++)
                                    {
                                        indexInCollection = useOnlyTheseDirs.IndexOf(listFinal[listFinal.Count - 1].files[e]);
                                        if (indexInCollection != -1)
                                        {
                                            break;
                                        }
                                    }
                                    if (indexInCollection == -1)
                                    {
                                        List<string> tmpList = listFinal[listFinal.Count - 1].files.ToList();
                                        tmpList.RemoveAt(e);
                                        listFinal[listFinal.Count - 1].files = tmpList.ToArray();
                                        e--;
                                        continue;
                                    }
                                }
                                if (I_AM_IDLE)
                                {
                                    break;
                                }
                                listFinal[listFinal.Count - 1].files[e] = Path.GetFileName(listFinal[listFinal.Count - 1].files[e]);
                            }

                            string[] novi_dir = Directory.GetDirectories(dirList[i][u]);
                            for (int e = 0; e < novi_dir.Length; e++)
                            {
                                if (i == 0 && useOnlyTheseDirs != null)
                                {
                                    if (!checkIfItIsDisk(useOnlyTheseDirs[0]))
                                    {
                                        int indexInCollection = -1;
                                        for (int b = 0; b < useOnlyTheseDirs.Count; b++)
                                        {
                                            indexInCollection = useOnlyTheseDirs.IndexOf(novi_dir[e]);
                                            if (indexInCollection != -1)
                                            {
                                                break;
                                            }
                                        }
                                        if (indexInCollection == -1)
                                        {
                                            continue;
                                        }
                                    }
                                }
                                if (I_AM_IDLE)
                                {
                                    break;
                                }
                                direktoriji.Add(novi_dir[e]);
                            }
                        }
                        catch (System.UnauthorizedAccessException)
                        {
                        }
                        if (I_AM_IDLE)
                        {
                            break;
                        }
                    }
                    if (I_AM_IDLE)
                    {
                        break;
                    }
                    if (direktoriji.Count > 0)
                    {
                        dirList.Add(direktoriji.ToArray());
                    }
                    else
                    {
                        for (int e = 0; e < listFinal.Count; e++)
                        {
                            int start = listFinal[e].root.IndexOf(root_folder, StringComparison.Ordinal) + root_folder.Length;

                            listFinal[e].root = listFinal[e].root.Substring(start, listFinal[e].root.Length - start);
                            if (string.IsNullOrEmpty(listFinal[e].root))
                            {
                                // listFinal[e].root = "\\";
                            }
                        }
                        if (useOnlyTheseDirs != null)
                        {
                            if (!checkIfItIsDisk(useOnlyTheseDirs[0]))
                            {
                                //  root_folder = string.Empty;
                                listFinal.old_root = string.Empty;
                            }
                        }                       
                        if (!I_AM_IDLE)
                        {
                            return listFinal;
                        }
                        else
                        {
                            break;
                        }
                    }
                }              
                return null;
            }
            finally
            {
                scanningFiles = false;
            }
           
        }
        static bool checkIfItIsDisk(string pathToDirectory)
        {
            /* System.Text.RegularExpressions.Regex checkIfItDisk = new System.Text.RegularExpressions.Regex(@"\\");
              System.Text.RegularExpressions.MatchCollection matchResults = checkIfItDisk.Matches(pathToDirectory); 
              return (matchResults.Count == 1);  
             */
            return Path.GetPathRoot(pathToDirectory).Equals(pathToDirectory, StringComparison.Ordinal);
                 
        }
        static string getStandardRootPath(string directoryPath)
        {
            if(!Directory.Exists(directoryPath))
            {
                directoryPath = Path.GetDirectoryName(directoryPath);
            }
            string[] spliting = directoryPath.Split(Path.PathSeparator);
            return ((!checkIfItIsDisk(path)) ? spliting[spliting.Length - 1] : directoryPath);       
        }
       delegate void pic_image(Bitmap bit);
       delegate void hide_image();
       delegate void number_update(bool advancePosition);
       static Bitmap readFromStreamReturnBitmap(WorkerBg thisWorker)
       {
           Bitmap loadedImage = null;
           using (MemoryStream returnedMemoryStream = NetworkControlerObject.getExchangeClassByIndex(thisWorker.NETWORK_INDEX).StartRead())
           {
               if (returnedMemoryStream != null && returnedMemoryStream.Length > 0)
               {
                   try
                   {
                       loadedImage = new Bitmap(System.Drawing.Image.FromStream(returnedMemoryStream));
                   }
                   catch (ArgumentException)
                   {
                       loadedImage = null;
                   }
               }             
           }
           return loadedImage;
       }
       static void readFromStreamReturnBitmap(WorkerBg thisWorker, ref Bitmap imageSize)
       {
           NetworkControlerObject.getExchangeClassByIndex(thisWorker.NETWORK_INDEX).StartRead(ref imageSize);        
       }      
       public static Bitmap FlattenAlphaChannel(Bitmap bitmapToFlatten)
       {
           if (bitmapToFlatten != null)
           {
               Rectangle areaToFlaten = new Rectangle(0, 0, bitmapToFlatten.Width, bitmapToFlatten.Height);
               BitmapData bitmapDataObject = bitmapToFlatten.LockBits(areaToFlaten, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
               IntPtr startOfImage = bitmapDataObject.Scan0;
               for (int i = 3; i < bitmapDataObject.Stride * bitmapDataObject.Height; i += 4)
               {
                   if (Marshal.ReadByte(startOfImage, i) < 255)
                   {
                       if (Marshal.ReadByte(startOfImage, i - 3) == 0 && Marshal.ReadByte(startOfImage, i - 2) == 0 && Marshal.ReadByte(startOfImage, i - 1) == 0)
                       {
                           Marshal.WriteByte(startOfImage, i - 3, 255);
                           Marshal.WriteByte(startOfImage, i - 2, 255);
                           Marshal.WriteByte(startOfImage, i - 1, 255);
                       }                      
                       Marshal.WriteByte(startOfImage, i, 255);
                   }                   
               }
               bitmapToFlatten.UnlockBits(bitmapDataObject);
           }
           return bitmapToFlatten;
       }
       public static Bitmap FlattenAlphaChannelSimple(Bitmap bitmapToFlatten)
       {
           Bitmap whiteBitmap = null;
           if (bitmapToFlatten != null)
           {
               Rectangle areaToFlaten = new Rectangle(0, 0, bitmapToFlatten.Width, bitmapToFlatten.Height);
               whiteBitmap = new Bitmap(areaToFlaten.Width, areaToFlaten.Height);
               Graphics graphics = Graphics.FromImage(whiteBitmap);
               graphics.FillRectangle(new SolidBrush(Color.White), areaToFlaten);
               graphics.DrawImage(bitmapToFlatten, areaToFlaten);
               graphics.Dispose();
               bitmapToFlatten.Dispose();
           }
           return whiteBitmap;
       }
       public static Size GetNewImageSize(Size currentSize)
       {
           Size pictureSize = Size.Empty;
           if (width == 0)
           {
               if (height < currentSize.Height)
               {
                   double faktor = (double)currentSize.Width / (double)currentSize.Height;
                   pictureSize = new Size((int)(height * faktor), height);
                   if (pictureSize.Width == 0)
                   {
                       pictureSize = new Size(1, (int)(1 / faktor));
                   }
               }
               else
               {
                   pictureSize = currentSize;
               }               
           }
           else if (height == 0)
           {
               if (width < currentSize.Width)
               {
                   double faktor = (double)currentSize.Height / (double)currentSize.Width;
                   pictureSize = new Size(width, (int)(width * faktor));
                   if (pictureSize.Height == 0)
                   {
                       pictureSize = new Size((int)(1 / faktor), 1);
                   }
               }
               else
               {
                   pictureSize = currentSize;
               }
           }
           return pictureSize;
       }
       static public string swapExtension(string full, string newExt)
       {
           return Path.GetDirectoryName(full) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(full) + "." + newExt;
       }
       static void writeNewEncoderParams()
       {
           myEncoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, q);
           myEncoderParameters.Param[1] = compression_par;
           myEncoderParameters.Param[2] = ColorDepth_par;
           myEncoderParameters.Param[3] = RenderMethod_par;
           myEncoderParameters.Param[4] = ScanMethod_par;
       }
       void  back_DoWork(object sender, DoWorkEventArgs e)
       {
           WorkerBg thisWorker = (WorkerBg)sender;
           if (thisWorker.isWorkerNetwork)
           {
               thisWorker.myCore = NetworkControlerObject.getExchangeClassByIndex(thisWorker.NETWORK_INDEX);
               if (thisWorker.myCore != null)
               {
                   thisWorker.myCore.myThread = thisWorker;
               }
           }
           writeNewEncoderParams();
           Int64 currentQuality = q;
           int size = thisWorker.setOrGetSize;
           ImageResizerGPGPU.MainForm.ListFiles.ListFilePathAndCodec files_sort_f = workingThreads.listOfFiles;
           string root_folder = string.Empty;
           bool errorSettingUp = false;
           if(!one_image && MASTER)
           {
               if (workingThreads.Data != null)
               {
                   root_folder = workingThreads.Data.old_root;
               }
               else
               {
                   errorSettingUp = true;
               }
           }
           List<int> listOfReadOnlyFiles = new List<int>();
           if (thisWorker.setOrGetStartIndex == 0)
           {
               number_update num = new number_update(update_number);
               workingThreads.refToParent.BeginInvoke(num, true);
           }
           int previousLoopNumber = -1;
           int averageBufferSize = 4096;
           int allBufferSize = 4096;
           int lastBufferAdditionLoopNumber = -1;
           int resourceProblem = 0;
           int memoryOutLoading = 0;
           for (int loopNumber = thisWorker.setOrGetStartIndex, buffersFinished = 1; !errorSettingUp && !I_AM_IDLE && loopNumber < size; loopNumber++, buffersFinished++)
           {
               try
               {
                   if (workingThreads.backWorkers.Count == 0)
                   {
                       break;
                   }
                   Bitmap loadedImage = null;
                   Size pictureSize = Size.Empty;
                   if (thisWorker.isWorkerNetwork && thisWorker.disconnectNetwork)
                   {
                       thisWorker.isWorkerNetworkNoMore();
                   }
                   if (thisWorker.isWorkerNetwork && previousLoopNumber == loopNumber)
                   {
                       string messageToSend = string.Empty;
                       if (MASTER)
                       {
                           messageToSend = thisWorker.myCore.PORT.ToString(CultureInfo.InvariantCulture) + ";" + (loopNumber - thisWorker.setOrGetStartIndex).ToString(CultureInfo.InvariantCulture);
                       }
                       else
                       {
                           messageToSend = "MASTER?;" + thisWorker.myCore.PORT.ToString(CultureInfo.InvariantCulture);
                       }
                       if (!thisWorker.myCore.sendDataToCore("8" + messageToSend))
                       {
                           if (MASTER)
                           {
                               thisWorker.isWorkerNetworkNoMore();
                           }
                           else
                           {
                               voidDelegate voidPointer = new voidDelegate(stopAll);
                               if (thisWorker != null && thisWorker.myCore != null)
                               {
                                   MainForm.Instance().Invoke(voidPointer);
                               }
                           }
                       }
                   }
                   else if (previousLoopNumber == loopNumber)
                   {
                       buffersFinished--;
                   }
                   previousLoopNumber = loopNumber;
                   string originalAbsolutePath = path + files_sort_f[loopNumber].filePath;
                   if (MASTER)
                   {
                       try
                       {
                           if (!one_image && String.IsNullOrEmpty(files_sort_f[loopNumber].filePath))
                           {
                               break;
                           }
                           using (FileStream fileStreamObject = new System.IO.FileStream(originalAbsolutePath, System.IO.FileMode.Open))
                           {
                               using (MemoryStream writeToMemomyStream = new MemoryStream(averageBufferSize))
                               {
                                   byte[] data = new byte[averageBufferSize];
                                   for (int z = 0, bytesRead = 0; (bytesRead = fileStreamObject.Read(data, 0, data.Length)) > 0; z++)
                                   {
                                       writeToMemomyStream.Write(data, 0, bytesRead);
                                   }
                                   if (thisWorker.isWorkerNetwork) // send data
                                   {
                                       data = writeToMemomyStream.GetBuffer();
                                       if (!thisWorker.myCore.StartWrite(data))
                                       {
                                           loopNumber--;
                                           continue;
                                       }
                                       readFromStreamReturnBitmap(thisWorker, ref loadedImage);
                                       if (loadedImage == null)
                                       {
                                           loopNumber--;
                                           continue;
                                       }
                                   }
                                   else
                                   {
                                       try
                                       {
                                           loadedImage = new Bitmap(writeToMemomyStream);
                                           pictureSize = GetNewImageSize(loadedImage.Size);
                                       }
                                       catch (ArgumentException) // image corrupted,raw
                                       {
                                           continue;
                                       }
                                       catch(OutOfMemoryException)
                                       {
                                           GC.Collect();                                                                                      
                                           if (memoryOutLoading < 4)
                                           {
                                               memoryOutLoading++;
                                               Thread.Sleep(100 * memoryOutLoading);                                               
                                               loopNumber--;
                                           }
                                           else
                                           {
                                               memoryOutLoading = 0;
                                           }
                                           continue;
                                       }
                                       memoryOutLoading = 0;
                                   }
                                   if (lastBufferAdditionLoopNumber != loopNumber)
                                   {
                                       allBufferSize +=  (int)writeToMemomyStream.Length;
                                       averageBufferSize = allBufferSize / buffersFinished;
                                       lastBufferAdditionLoopNumber = loopNumber;
                                   }
                               }                                                           
                           }
                       }
                       catch (System.UnauthorizedAccessException)
                       {
                           bool continueIgnoreFile = false;
                           FileInfo checkFile = new FileInfo(originalAbsolutePath);
                           if (checkFile.IsReadOnly)
                           {
                               try
                               {
                                   checkFile.IsReadOnly = false;
                                   listOfReadOnlyFiles.Add(loopNumber);
                                   loopNumber--;
                               }
                               catch (UnauthorizedAccessException)
                               {
                                   continue;
                               }
                           }
                           else if (listOfReadOnlyFiles.Contains(loopNumber))
                           {
                               listOfReadOnlyFiles.Remove(loopNumber);
                               checkFile.IsReadOnly = true;
                               continueIgnoreFile = true;
                           }
                           else
                           {
                               continueIgnoreFile = true;
                           }
                           if (continueIgnoreFile && !DISPOSED)
                           {
                               System.Threading.Interlocked.Increment(ref workingThreads.progressPosition);
                           }
                           continue;
                       }
                       catch (IOException) { }
                       catch (ArgumentException) { }
                   }
                   else
                   {
                       if (thisWorker.isWorkerNetwork)
                       {

                           int newLoopNumber = thisWorker.myCore.getSyncLoop(loopNumber);
                           if (loopNumber != newLoopNumber)
                           {
                               loopNumber = newLoopNumber;
                               continue;
                           }
                           loadedImage = readFromStreamReturnBitmap(thisWorker);
                           if (loadedImage == null)
                           {
                               loopNumber--;
                               continue;
                           }
                           else
                           {
                               pictureSize = GetNewImageSize(loadedImage.Size);
                           }
                       }
                   }
                   if (MASTER && !thisWorker.isWorkerNetwork || !MASTER && thisWorker.isWorkerNetwork)
                   {
                       bool GPU_RESOURCE_PROBLEM = false;
                       bool useGPU = thisWorker.USE_GPU && (IsOpenCLEnabled || CUDA_OBJECT.CV_CUDA_ENABLED); 
                       if (useGPU)
                       {        
                           if (IsOpenCLEnabled)
                           {
                               try
                               {
                                   loadedImage = CreateOpenCLImages(loadedImage, pictureSize);
                                   resourceProblem = 0;
                               }
                               catch (Exception ex /*OpenCLException errorCode*/)
                               {
                                   
                                   if (resourceProblem > 2 && /*(errorCode.ErrorCode == ErrorCode.OUT_OF_HOST_MEMORY || errorCode.ErrorCode == ErrorCode.OUT_OF_RESOURCES)*/
                                       ex.GetType().Equals(typeof(OpenCLException)) || ex.GetType().Equals(typeof(OutOfMemoryException)))
                                   {
                                       GPU_RESOURCE_PROBLEM = true;
                                       resourceProblem = 0;
                                       GC.Collect();
                                   }
                                   else
                                   {                                       
                                       resourceProblem++;
                                       Thread.Sleep(100 * resourceProblem);
                                       loopNumber--;
                                       continue;
                                   }
                               }
                           }
                           else if (CUDA_OBJECT.CV_CUDA_ENABLED)
                           {
                               try
                               {
                                   loadedImage = CUDA.getResizedImage(pictureSize, loadedImage);
                                   resourceProblem = 0;
                               }
                               catch (OutOfMemoryException)
                               {
                                   if (resourceProblem > 2)
                                   {
                                       GPU_RESOURCE_PROBLEM = true;
                                       resourceProblem = 0;
                                       GC.Collect();
                                   }
                               }
                               if (!GPU_RESOURCE_PROBLEM && loadedImage == null)
                               {
                                   resourceProblem++;
                                   Thread.Sleep(100 * resourceProblem);
                                   loopNumber--;
                                   continue;
                               }
                           }                                               
                       }
                       if (!useGPU || GPU_RESOURCE_PROBLEM)
                       {
                           try
                           {
                               Bitmap loadedImageTemp = new Bitmap(ResizeImage(loadedImage, pictureSize.Width, pictureSize.Height));
                               if (loadedImage != null)
                               {
                                   loadedImage.Dispose();
                               }
                               loadedImage = loadedImageTemp;
                               if (GPU_RESOURCE_PROBLEM)
                               {
                                   GPU_RESOURCE_PROBLEM = false;
                               }
                           }
                           catch (OutOfMemoryException)
                           {
                               loopNumber--;
                               GC.Collect();
                               continue;
                           }
                       }                     
                   }                    
                   string full = string.Empty;
                   if (MASTER)
                   {
                       if (one_image)
                       {
                           full = save_folder_path;
                       }
                       else
                       {
                           string rootOld = workingThreads.Data.regexObject.Replace(root_folder, string.Empty);
                           if (!string.IsNullOrEmpty(rootOld))
                           {
                               rootOld = Path.DirectorySeparatorChar + rootOld;
                           }
                           string sortPath = files_sort_f[loopNumber].sortPath;
                           if (!string.IsNullOrEmpty(sortPath))
                           {
                               sortPath = Path.DirectorySeparatorChar + sortPath;
                           }
                           if (!ignoreSubFoldersCheckBox.Checked)
                           {
                               full = save_folder_path + rootOld + files_sort_f[loopNumber].root + sortPath + Path.DirectorySeparatorChar + files_sort_f[loopNumber].fileName.Replace(":", string.Empty);
                           }
                           else
                           {
                               string fileName = files_sort_f[loopNumber].fileName.Replace(":", string.Empty);
                               if (files_sort_f[loopNumber].uniqueIndex > 0)
                               {
                                   fileName = Path.GetFileNameWithoutExtension(fileName) + "_" + files_sort_f[loopNumber].uniqueIndex.ToString() + Path.GetExtension(fileName);
                               }
                               full = save_folder_path + sortPath + Path.DirectorySeparatorChar + fileName;                              
                           }
                       }
                   }
                   if (!one_image && ImageResizerGPGPU.Properties.Settings.Default.alwaysSaveAsJpeg &&
                       flatenImagesWithIndex.Contains(files_sort_f[loopNumber].codecIndex) ||
                       one_image && (!flatenImagesWithIndex.Contains(oneImageCodec[1]) || oneImageCodec[1] ==3) && flatenImagesWithIndex.Contains(oneImageCodec[0]))
                   {                      
                       loadedImage = FlattenAlphaChannelSimple(loadedImage);                       
                       files_sort_f[loopNumber].codecIndex = 0;
                       if (one_image)
                       {
                           files_sort_f[loopNumber].codecIndex = oneImageCodec[1];
                       }
                       full = swapExtension(full, alowedCodecNames[files_sort_f[loopNumber].codecIndex].ToLowerInvariant());
                   }
                   if (!MASTER && thisWorker.isWorkerNetwork)
                   {
                       using (MemoryStream mem = new MemoryStream(1024000))
                       {
                           Rectangle newImageRectangle = new Rectangle(Point.Empty, loadedImage.Size);
                           BitmapData newImageData = loadedImage.LockBits(newImageRectangle, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                           if (!thisWorker.myCore.StartWrite(newImageData.Scan0, newImageData.Stride * newImageData.Height, loadedImage.Size))
                           {
                               loadedImage.Dispose();
                               loopNumber--;
                               continue;
                           }
                           loadedImage.UnlockBits(newImageData);
                       }
                   }
                   else
                   {
                       try
                       {
                           if (CheckForValidPath(full))
                           {
                               if (!File.Exists(full))
                               {
                                   loadedImage.Save(full, imageCodecs[files_sort_f[loopNumber].codecIndex], myEncoderParameters);
                                   //  setFileDetails(originalAbsolutePath, 0, full, files_sort_f[loopNumber].codecIndex);
                               }
                               else if (overwrite)
                               {
                                   File.Delete(full);
                                   loadedImage.Save(full, imageCodecs[files_sort_f[loopNumber].codecIndex], myEncoderParameters);
                               }
                           }
                       }
                       catch (IOException) { }
                       catch (ExternalException) { }
                   }
                   if (loadedImage != null)
                   {
                       loadedImage.Dispose();
                   }
                   else
                   {
                       loopNumber--;
                       continue;
                   }
                   while (THREADS_ARE_PAUSED)
                   {
                       Thread.Sleep(500);
                       if (currentQuality != q)
                       {
                           writeNewEncoderParams();
                       }
                   }
                   if (!DISPOSED)
                   {
                       System.Threading.Interlocked.Increment(ref workingThreads.progressPosition);
                    
                   }
                   else
                   {
                       break;
                   }
               }
               catch (OutOfMemoryException)
               {
                   loopNumber--;
               }
               catch (ObjectDisposedException)
               {
                   break;
               }
               catch (NullReferenceException)
               {
                   break;
               }
           }
           if (!DISPOSED && listOfReadOnlyFiles.Count > 0)
           {
               for (int i = 0; i < listOfReadOnlyFiles.Count; i++ )
               {
                   FileInfo resetReadOnlyBack = new FileInfo(path + files_sort_f[listOfReadOnlyFiles[i]].filePath);
                   resetReadOnlyBack.IsReadOnly = true;
               }
           }
       }    
       static void setFileDetails(string originalPathToFile, int originalCodecIndex, string newPathToFile, int newCodecIndex)
       {
           // "JPEG", "BMP", "PNG", "GIF", "TIFF" 
           System.Windows.Media.Imaging.BitmapFrame imageFrame = null;         
           System.IO.Stream imageStream = new System.IO.FileStream(originalPathToFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
           System.Windows.Media.Imaging.BitmapMetadata originalMetaData = new System.Windows.Media.Imaging.BitmapMetadata(alowedCodecNames[originalCodecIndex]);
           getBitmapFrame(originalCodecIndex, out imageFrame, imageStream);
           
           imageStream.Dispose();
           imageStream = new System.IO.FileStream(newPathToFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
           //System.Windows.Media.Imaging.BitmapMetadata originalMetaData = new System.Windows.Media.Imaging.BitmapMetadata(alowedCodecNames[originalCodecIndex]);
           getBitmapFrame(originalCodecIndex, out imageFrame, imageStream);

           System.Windows.Media.Imaging.InPlaceBitmapMetadataWriter saveImageInplace = imageFrame.CreateInPlaceBitmapMetadataWriter();
           if (saveImageInplace.TrySave() == true)
           { 
               saveImageInplace.SetQuery("/Text/Comments", "Converted with Image Resizer GPGPU."); 
           }
           imageStream.Close();       
         
        }
       static void getBitmapFrame(int codecIndex, out System.Windows.Media.Imaging.BitmapFrame imageFrame, System.IO.Stream imageStream)
       {
           if (codecIndex == 0)
           {
               System.Windows.Media.Imaging.JpegBitmapDecoder jpegDecoder = new System.Windows.Media.Imaging.JpegBitmapDecoder(imageStream,
                   System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat,
                   System.Windows.Media.Imaging.BitmapCacheOption.Default);
               imageFrame = jpegDecoder.Frames[0];
           }
           else if (codecIndex == 1)
           {
               System.Windows.Media.Imaging.BmpBitmapDecoder bmpDecoder = new System.Windows.Media.Imaging.BmpBitmapDecoder(imageStream,
                   System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat,
                   System.Windows.Media.Imaging.BitmapCacheOption.Default);
               imageFrame = bmpDecoder.Frames[0];
           }
           else if (codecIndex == 2)
           {
               System.Windows.Media.Imaging.PngBitmapDecoder pngDecoder = new System.Windows.Media.Imaging.PngBitmapDecoder(imageStream,
                   System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat,
                   System.Windows.Media.Imaging.BitmapCacheOption.Default);
               imageFrame = pngDecoder.Frames[0];
           }
           else if (codecIndex == 3)
           {
               System.Windows.Media.Imaging.GifBitmapDecoder gifDecoder = new System.Windows.Media.Imaging.GifBitmapDecoder(imageStream,
                   System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat,
                   System.Windows.Media.Imaging.BitmapCacheOption.Default);
               imageFrame = gifDecoder.Frames[0];
           }
           else if (codecIndex == 4)
           {
               System.Windows.Media.Imaging.TiffBitmapDecoder tiffDecoder = new System.Windows.Media.Imaging.TiffBitmapDecoder(imageStream,
                   System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat,
                   System.Windows.Media.Imaging.BitmapCacheOption.Default);
               imageFrame = tiffDecoder.Frames[0];
           }
           else
           {
               imageFrame = null;
           }
       }
       public static Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
        {
            Bitmap bitmapOriginal=null;
            Bitmap bitmapTemp = null;
            try
            {
                bitmapTemp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
                Graphics g = Graphics.FromImage((System.Drawing.Image)bitmapTemp);
                g.DrawImage(image, 0, 0, width, height);
                g.Dispose();
                bitmapOriginal = bitmapTemp;
                bitmapTemp = null;
            }
            finally
            {
                if (bitmapTemp != null)
                {
                    bitmapTemp.Dispose();
                }
            }
            return bitmapOriginal;
        }
        private static int GetEncoder(string format)
        {           
           format = format.ToUpperInvariant();
            for (int i = 0; i < imageCodecs.Length; i++)
            {
                if (imageCodecs[i].FilenameExtension.Contains(format))
                {
                    return i;
                }
            }
            return 1;
        }
        static string[] alowedCodecNames = { "JPEG", "BMP", "PNG", "GIF", "TIFF" };
        static int[] flatenImagesWithIndex = {2,3,4};
        static void listCodecsForFileFilter()
        {
            ImageCodecInfo[] imageCodecsSorted = new ImageCodecInfo[alowedCodecNames.Length];
            for(int i=0;  i < alowedCodecNames.Length; i++)
            {
                for(int u = 0; u < imageCodecs.Length; u++)
                {
                    if (alowedCodecNames[i].Contains(imageCodecs[u].FormatDescription))
                    {
                        imageCodecsSorted[i] = imageCodecs[u];
                        fileNameOpenFilter += imageCodecs[u].FilenameExtension + ";";
                        fileNameSaveFilter += imageCodecs[u].CodecName + "|" + imageCodecs[u].FilenameExtension + "|";
                    }              
                }
            }
            imageCodecs = imageCodecsSorted;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            this.TopMost = false;
            using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
            {
                folderDialog.Description = "Open";
                folderDialog.ShowDialog();
                if (!string.IsNullOrEmpty(folderDialog.SelectedPath))
                {
                    path = folderDialog.SelectedPath.ToString();                    
                    start.Enabled = true;                    
                    one_image = false;
                    start_Click(null, null);
                }
            }
            alwaysOnTopCheckBox_CheckedChanged(null, null);
        }
        public static string GetUniqueValidFileName(string pathToFile, string addThisAtTheEnd)
        {
            for (int p=0; ;p++)
            {
                string newNameToReturn = Path.GetDirectoryName(pathToFile) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(pathToFile) + addThisAtTheEnd + ((p == 0) ? string.Empty : "_" + p.ToString(CultureInfo.InvariantCulture)) + Path.GetExtension(pathToFile);
                if (!File.Exists(newNameToReturn))
                {
                    return Path.GetFileName(newNameToReturn);
                }
            }
        }
        private static void disconnectAndDoLocalWork()
        {
            if (!I_AM_IDLE && !MASTER)
            {
                if (workingThreads != null)
                {
                    workingThreads.Dispose();
                }
                NetworkControlerObject.resetClass();
                I_AM_IDLE = true;
                MASTER = true;
                THREADS_ARE_PAUSED = false;
            }
        }
        void SettingsEnabledState()
        {
            sortByDayCheckBox.Enabled = I_AM_IDLE;
            sortByWeekCheckBox.Enabled = I_AM_IDLE;
            sortByMonthCheckBox.Enabled = I_AM_IDLE;
            sortByYearCheckBox.Enabled = I_AM_IDLE;
            ignoreSubFoldersCheckBox.Enabled = I_AM_IDLE;
        }
        delegate void BoolDelegate(bool boolValue);
        private void pauseResumeProgram(bool resetToStartState)
        {
            if (!resetToStartState)
            {
                THREADS_ARE_PAUSED = !THREADS_ARE_PAUSED;
                textBoxImageHeight.Enabled = THREADS_ARE_PAUSED;
                textBoxImageWidth.Enabled = THREADS_ARE_PAUSED;
                qualityTrackBar.Enabled = THREADS_ARE_PAUSED;
                if (THREADS_ARE_PAUSED)
                {
                    start.Text = getResourceString("StartButtonResume", myLanguage);
                }
                else
                {
                    start.Text = getResourceString("StartButtonPause", myLanguage);
                }
            }
            else
            {                
                THREADS_ARE_PAUSED = false;
                MASTER = true;
                I_AM_IDLE = true;                  
                textBoxImageHeight.Enabled = true;
                textBoxImageWidth.Enabled = true;
                qualityTrackBar.Enabled = true;
                selectToolStripMenuItemSelect.Enabled = true;
                start.Text = getResourceString("StartButtonText", myLanguage);
                start.Enabled = false;
            }
            SettingsEnabledState();
            if (!I_AM_IDLE)
            {
                pauseResumeAllTheads(THREADS_ARE_PAUSED);
            }
        }
        private void start_Click(object sender, EventArgs e)
        {
            bool justStop = false;
            if (!MASTER)
            {
                if (sender != null)
                {
                    using (ToolStripMenuItem tmpObj = new ToolStripMenuItem())
                    {
                        justStop = (Object.ReferenceEquals(sender.GetType(), ((object)tmpObj).GetType()));
                    }
                }
                noMoreSlave();
            }
            if (!justStop)
            {
                List<string> useOnlyTheseDirs = null;
                if (sender != null)
                {
                    if (Object.ReferenceEquals(sender.GetType(), ((object)new List<string>()).GetType()))
                    {
                        useOnlyTheseDirs = (List<string>)sender;
                    }
                }
                disconnectAndDoLocalWork();
                if (!THREADS_ARE_PAUSED)
                {
                    if (I_AM_IDLE)
                    {
                        bool status_ok = false;
                        this.TopMost = false;
                        if (!one_image)
                        {
                            using (FolderBrowserDialog save_folder = new FolderBrowserDialog())
                            {
                                save_folder.Description = "Save To";
                                if (save_folder.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                                {
                                    save_folder_path = save_folder.SelectedPath;
                                    status_ok = true;
                                }
                            }
                        }
                        else
                        {
                            using (SaveFileDialog saveFileTo = new SaveFileDialog())
                            {
                                saveFileTo.AddExtension = true;
                                saveFileTo.Filter = fileNameSaveFilter + "All files (*.*)|*.*";                               
                                oneImageCodec[0] = GetEncoder(Path.GetExtension(path));
                                if (!ImageResizerGPGPU.Properties.Settings.Default.alwaysSaveAsJpeg)
                                {
                                    saveFileTo.FileName = GetUniqueValidFileName(path, "_small");
                                    saveFileTo.FilterIndex = oneImageCodec[0] + 1;
                                }
                                else
                                {
                                    saveFileTo.FileName = Path.GetFileNameWithoutExtension(GetUniqueValidFileName(path, "_small")) + "." + alowedCodecNames[0].ToLowerInvariant();
                                    saveFileTo.FilterIndex = 0;
                                }                                
                                if (saveFileTo.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                                {
                                    save_folder_path = saveFileTo.FileName;
                                    oneImageCodec[1] = GetEncoder(Path.GetExtension(save_folder_path));
                                    status_ok = true;
                                }
                            }
                        }
                        alwaysOnTopCheckBox_CheckedChanged(null, null);
                        statusAndList inputData;
                        inputData.status_ok = status_ok;
                        inputData.useOnlyTheseDirs = useOnlyTheseDirs;
                        inputData.mainRef = this;
                        ThreadPool.QueueUserWorkItem(new WaitCallback(startConvertingImages), inputData);
                    }
                    else
                    {
                        pauseResumeProgram(false);
                    }
                }
                else
                {
                    pauseResumeProgram(false);
                }
            }
        }
        void noMoreSlave()
        {
            stopAll();           
            initializeSettings();          
        }
        void stopAll()
        {
            if (!MASTER)
            {
                save_folder_path = string.Empty;
            }
            else if (workingThreads != null && workingThreads.listOfFiles != null)
            {
                if (workingThreads.progressPosition != workingThreads.listOfFiles.Count || workingThreads.listOfFiles.Count == 0)
                {
                    save_folder_path = string.Empty;
                }
            }
            else
            {
                save_folder_path = string.Empty;
            }
            this.selectToolStripMenuItemSelect.Enabled = true;
            this.selectToolStripMenuItemSelect.ForeColor = Color.White;
            this.selectToolStripMenuItemSelect.Text = getResourceString("selectButton", myLanguage);
            if (workingThreads != null)
            {
                workingThreads.Dispose();
            }
            NetworkControlerObject.resetClass();
            pauseResumeProgram(true);
            progressPicturesBox.Invalidate();
            
        }
        static void pauseResumeAllTheads(bool pauseItNow)
        {
            for (int i = 0; i < NetworkControlerObject.ExchangeClassList.Count; i++)
            {
                if (pauseItNow)
                {
                    NetworkControlerObject.ExchangeClassList[i].PAUSE();
                }
                else
                {
                    NetworkControlerObject.ExchangeClassList[i].RESUME();
                }
            }
        }
        struct statusAndList
        {
            public bool status_ok;
            public List<string> useOnlyTheseDirs;
            public MainForm mainRef;
        };
        void startWorkingSetGui()
        {
            this.selectToolStripMenuItemSelect.Enabled = true;
            this.selectToolStripMenuItemSelect.ForeColor = mainBackgroundColor[1];
            this.selectToolStripMenuItemSelect.Text = getResourceString("stopLabel", myLanguage);    
            textBoxImageHeight.Enabled = false;
            textBoxImageWidth.Enabled = false;
            THREADS_ARE_PAUSED = false;
            qualityTrackBar.Enabled = false;
            SettingsEnabledState();
        }
        void showStartPauseButton()
        {
            start.Enabled = true;
            start.Tag = true;
            start.Text = getResourceString("StartButtonPause", myLanguage);
        }
        private void startConvertingImages(object data)
        {
            statusAndList inputObjects = (statusAndList)data;
            if (inputObjects.status_ok)
            {
                I_AM_IDLE = false;
                voidDelegate voidPointer = new voidDelegate(startWorkingSetGui);
                MainForm.Instance().Invoke(voidPointer);               
                workingThreads = new ListOfBgWorkers(this, inputObjects.useOnlyTheseDirs);
                if (workingThreads.listOfFiles.Count > 0 && !I_AM_IDLE)
                {                    
                    if (!one_image)
                    {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(NetworkControlerObject.refreshPartners), null);
                    }
                    else
                    {                       
                        workingThreads.initialize();
                    }                   
                }
                else
                {
                    BoolDelegate boolPointer = new BoolDelegate(MainForm.Instance().pauseResumeProgram);
                    MainForm.Instance().Invoke(boolPointer, true);                    
                    if (I_AM_IDLE)
                    {
                        MessageBox.Show(getResourceString("NoImagesFound", myLanguage), getResourceString("NoImagesFoundTitle", myLanguage), MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
                    }                  
                    if (workingThreads != null)
                    {
                        workingThreads.Dispose();
                    }
                }
            }     
        }
        static bool isValidNumber(string checkString, int startPosition)
        {
            if (string.IsNullOrEmpty(checkString) || checkString.Length > 6 ||
                 startPosition < 2 && checkString[0] == '0')
            {
                return false;
            }
            char[] charNumbers = {'0','1','2','3','4','5','6','7','8','9'};
            for (int i = 0; i < checkString.Length; i++)
            {
                if (!charNumbers.Contains(checkString[i]))
                {
                    return false;
                }
            }           
            return true;
        }
        private void textheight_TextChanged(object sender, EventArgs e)
        {
            TextBox thisTextBox = (TextBox)sender;
            TextBox otherTextBox = null;
            bool isHeight = true;
            if (thisTextBox.Equals(textBoxImageHeight))
            {
                otherTextBox = textBoxImageWidth;
            }
            else
            {
                otherTextBox = textBoxImageHeight;
                isHeight = false;
            }

            if (thisTextBox.Text.Length > 1)
            {
                if (thisTextBox.Text.EndsWith(addSlash, StringComparison.Ordinal))
                {
                    thisTextBox.Text = thisTextBox.Text.Substring(0, thisTextBox.Text.Length - 1);
                    thisTextBox.SelectionStart = thisTextBox.Text.Length;
                }
                else if (thisTextBox.Text.StartsWith(addSlash, StringComparison.Ordinal))
                {
                    thisTextBox.Text = thisTextBox.Text.Substring(1, thisTextBox.Text.Length - 1);
                    thisTextBox.SelectionStart = thisTextBox.Text.Length;
                }
            }
            if (isValidNumber(thisTextBox.Text, thisTextBox.SelectionStart))
            {
                if (isHeight)
                {
                    height = Convert.ToInt32(thisTextBox.Text, CultureInfo.InvariantCulture);
                    thisTextBox.Tag = height;
                    width = 0;
                }
                else
                {
                    width = Convert.ToInt32(thisTextBox.Text, CultureInfo.InvariantCulture);
                    thisTextBox.Tag = width;
                    height = 0;
                }
                if (otherTextBox.Text != addSlash)
                {
                    otherTextBox.Text = addSlash;
                    otherTextBox.SelectionStart = otherTextBox.Text.Length;
                }
                thisTextBox.Tag = thisTextBox.Text;
            }
            else
            {                
                if (otherTextBox.Text == addSlash)
                {
                    string textTemp = thisTextBox.Text;
                    int selectionPositionTemp = thisTextBox.SelectionStart;
                    thisTextBox.Text = Convert.ToInt32(thisTextBox.Tag, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture);
                    if (!string.IsNullOrEmpty(textTemp))
                    {
                        thisTextBox.SelectionStart = ((selectionPositionTemp>0) ? selectionPositionTemp-1 : 0);
                    }
                    else
                    {
                        thisTextBox.SelectAll();
                    }
                    if (isHeight)
                    {
                        width = 0;
                        height = Convert.ToInt32(thisTextBox.Tag,CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        height = 0;
                        width = Convert.ToInt32(thisTextBox.Tag, CultureInfo.InvariantCulture);
                    }
                }
                else
                {
                    thisTextBox.Text = addSlash;
                    thisTextBox.SelectionStart = thisTextBox.Text.Length;
                    if (isHeight)
                    {
                        height = 0;
                        width = Convert.ToInt32(otherTextBox.Tag,CultureInfo.InvariantCulture);
                    }
                    else
                    {                       
                        width = 0;
                        
                        height = Convert.ToInt32(otherTextBox.Tag, CultureInfo.InvariantCulture);
                    }
                }
            }
            if (MASTER)
            {
                ImageResizerGPGPU.Properties.Settings.Default.width = width;
                ImageResizerGPGPU.Properties.Settings.Default.height = height;
            }
        }
        private void textheight_Click(object sender, EventArgs e)
        {
             TextBox thisTextBox = (TextBox)sender;
             if (thisTextBox.Text == addSlash)
             {
                 thisTextBox.SelectionStart = thisTextBox.Text.Length;
             }
             else
             {
                 thisTextBox.SelectAll();
             }
        }   
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            overwrite = overwriteCheckBox.Checked;
        }        
        private void imageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.TopMost = false;
            using (OpenFileDialog selectImageDialog = new OpenFileDialog())
            {
                selectImageDialog.Multiselect = true;
                selectImageDialog.Filter = "Images|" + fileNameOpenFilter + "|All files (*.*)|*.*"; ;                
                selectImageDialog.ShowDialog();                
                if (!string.IsNullOrEmpty(selectImageDialog.FileName))
                {                    
                    path = selectImageDialog.FileName.ToString();
                    start.Enabled = true;
                    if (selectImageDialog.FileNames.Length == 1)
                    {
                        one_image = true;
                        start_Click(null, null);
                    }
                    else
                    {
                        one_image = false;
                        path = getStandardRootPath(selectImageDialog.FileName.ToString());
                        start_Click(new List<string>(selectImageDialog.FileNames), null);
                    }
                }
            }
            alwaysOnTopCheckBox_CheckedChanged(null, null);
        }
        public void BeSlave()
        {
            setCurrentSettings();
            this.textBoxImageHeight.Enabled = false;
            this.textBoxImageWidth.Enabled = false;
            start.Text = getResourceString("stopLabel", myLanguage);
            start.Enabled = true;
        }       
        void qualityTrackBar_ValueChanged(object sender, EventArgs e)
        {
            imageQualityLabel.Text = getResourceString("ImageQualityLabel", myLanguage) + qualityTrackBar.Value.ToString(CultureInfo.InvariantCulture) + procent;
            q = Convert.ToInt64(qualityTrackBar.Value, CultureInfo.InvariantCulture);
            if (MASTER)
            {
                ImageResizerGPGPU.Properties.Settings.Default.quality = q;
            }
        }
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://imageresizergpgpu.codeplex.com/");
        }
        private void saveCurrentStateButton_Click(object sender, EventArgs e)
        {
            ImageResizerGPGPU.Properties.Settings.Default.Save();
        }
        private void selectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MASTER && !I_AM_IDLE)
            {
                stopAll();              
            }
        }
        private void progressPicturesBox_Click(object sender, EventArgs e)
        {
            if (path != null && MASTER && !String.IsNullOrEmpty(save_folder_path) && Path.IsPathRooted(save_folder_path))
            {
                if (Directory.Exists(save_folder_path) || File.Exists(save_folder_path))
                {
                    System.Diagnostics.Process.Start(save_folder_path);
                }
            }
        }
        class SettingsLabel : Label
        {
            private MainForm mainFormRef;
            public void initialize(MainForm mainFormRef, string resourceTextName)
            {
                if (!string.IsNullOrEmpty(resourceTextName))
                {
                    this.Text = getResourceString(resourceTextName, MainForm.myLanguage);
                }
                this.mainFormRef = mainFormRef;
            }
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                using(Pen myPen = new Pen(Color.Black))
                {
                    e.Graphics.DrawLine(myPen, new Point(0, this.Height - 2), new Point(this.Width, this.Height - 2));
                }
            }
        }
        partial class NiceTrackbar : PictureBox
        {
            public event EventHandler ValueChanged;
            private int maximum = 100;
            private int value = 90;
            private float currentDrawnValue = 90;
            private int lastCurrentStartDiff = 0;
            private bool mouseDown = false;
            System.Windows.Forms.Timer interpolationTimer = new System.Windows.Forms.Timer();
            int animationSpeed = 16;
            bool easing = true;
            public int Value
            {
                get
                {
                    return value;
                }
                set
                {
                    this.value = value;
                }
            }
            public int Maximum
            {
                get
                {
                    return maximum;
                }
                set
                {
                    this.maximum = value;
                }
            }
            void ValueChangedTrigger()
            {
                if (ValueChanged != null)
                {                  
                    ValueChanged(this, new EventArgs());
                }
            }            
            public NiceTrackbar()
            {
                SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
                interpolationTimer.Interval = 35;
                interpolationTimer.Tick += interpolationTimer_Tick;
                this.MouseDown += NiceTrackbar_MouseDown;
                this.MouseUp += NiceTrackbar_MouseUp;
                this.MouseMove += NiceTrackbar_MouseMove;
                Margin = new System.Windows.Forms.Padding(0);
                Padding = new Padding(0);
            }

            void NiceTrackbar_MouseMove(object sender, MouseEventArgs e)
            {
                if(mouseDown)
                {
                    OnClick(null);
                    this.Invalidate();
                }
            }

            void NiceTrackbar_MouseUp(object sender, MouseEventArgs e)
            {
                mouseDown = false;
            }

            void NiceTrackbar_MouseDown(object sender, MouseEventArgs e)
            {
                mouseDown = true;
            }

            void interpolationTimer_Tick(object sender, EventArgs e)
            {                
                float currentDiff = Math.Abs(this.Value - currentDrawnValue);
                float speedPercent = ((easing) ? (currentDiff / lastCurrentStartDiff) : 1);
                float animSpeed = animationSpeed * speedPercent;
                if (currentDrawnValue > this.Value)
                {
                    float remaining = currentDrawnValue - animSpeed;
                    if (remaining < Value)
                    {
                        animSpeed -= Value - remaining;
                    }
                    currentDrawnValue -= animSpeed;
                }
                else if (currentDrawnValue < this.Value)
                {
                    float remaining = currentDrawnValue + animSpeed;
                    if (remaining > Value)
                    {
                        animSpeed -=  remaining - Value;
                    }
                    currentDrawnValue += animSpeed;
                }
                else
                {
                    lock (interpolationTimer)
                    {
                        interpolationTimer.Stop();
                    }
                }
                this.Invalidate();
            }
            protected override void OnClick(EventArgs e)
            {
                base.OnClick(e);
                if (Enabled)
                {
                    Point posInMe = new Point(Cursor.Position.X - this.Left - MainForm.Instance().RealLeft,
                        Cursor.Position.Y - this.Top - MainForm.Instance().Top);
                    if (posInMe.X > this.Width)
                    {
                        posInMe.X = this.Width;
                    }
                    else if (posInMe.X < 0)
                    {
                        posInMe.X = 0;
                    }
                    int valueNew = (int)((posInMe.X / (float)this.Width) * 100);
                    if (Value != valueNew)
                    {
                        lastCurrentStartDiff = Math.Abs(Value - valueNew);
                        Value = valueNew;
                        this.Refresh();
                        ValueChangedTrigger();                        
                        lock (interpolationTimer)
                        {
                            interpolationTimer.Start();
                        }
                    }
                }
            }
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                float borderHalf = 0.5f;
                int borderSize = (int)(borderHalf * 2);
                e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
                e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
                using (SolidBrush myBrush = new SolidBrush(Color.Gray))
                {
                    e.Graphics.FillRectangle(myBrush, new Rectangle(0, 0, this.Width, this.Height));
                    float percent = this.currentDrawnValue / 100.0f; 
                    float widthProgress = percent * this.Width;
                    int alpha =(int)Math.Floor(255 * percent);
                    if(alpha > 255)
                    {
                        alpha = 255;
                    }
                    else if(alpha <50 )
                    {
                        alpha =50;
                    }
                    Color borderColor = Color.FromName("WindowFrame");
                    using (Pen borderPen = new Pen(Color.FromArgb(alpha, borderColor.R, borderColor.G, borderColor.B), borderSize))
                    {
                        e.Graphics.DrawRectangle(borderPen, new Rectangle((int)borderHalf, (int)borderHalf, this.Width - (int)borderPen.Width, this.Height - (int)borderPen.Width));
                    }                    
                   
                    using (SolidBrush myBrushProgress = new SolidBrush(mainBackgroundColor[1]))
                    {
                        e.Graphics.FillRectangle(myBrushProgress, new RectangleF(borderSize, borderSize, widthProgress - borderSize * 2, this.Height - borderSize * 2));
                    }
                }
               
            }
        }
        class ToggleButton : Button
        {
            private bool settingsVisible = false;
            private int thickness = 2;
            private MainForm mainFormRef;
            private bool mouseIsHover = false;
            private int closedHeight = 0;
            private int openedHeight = 0;
            private int[] MarginArrow = {5,5,5,5};
            public int MarginLeft
            {
                get
                {
                    return MarginArrow[0];
                }
                set
                {
                    MarginArrow[0] = value;
                }
            }
            public int MarginRight
            {
                get
                {
                    return MarginArrow[1];
                }
                set
                {
                    MarginArrow[1] = value;
                }
            }
            public int MarginTop
            {
                get
                {
                    return MarginArrow[2];
                }
                set
                {
                    MarginArrow[2] = value;
                }
            }
            public int MarginBottom
            {
                get
                {
                    return MarginArrow[3];
                }
                set
                {
                    MarginArrow[3] = value;
                }
            }
            public void initialize(MainForm mainFormRef, string resourceTextName)
            {
                if (!string.IsNullOrEmpty(resourceTextName))
                {
                    this.Text = getResourceString(resourceTextName, MainForm.myLanguage);
                }
                this.mainFormRef = mainFormRef;
            }         
            public void setHeightClosedOpened(int closedHeight, int openedHeight)
            {
                this.closedHeight = closedHeight;
                this.openedHeight = openedHeight;
            }
            private void toggleHover()
            {
                mouseIsHover = !mouseIsHover;
                this.Invalidate();
            }
            public void toggleSettings()
            {
                settingsVisible = !settingsVisible;
                this.Invalidate();
            }
            protected override void OnMouseClick(MouseEventArgs e)
            {
                base.OnMouseClick(e);
                ToggleSettingsView();
            }
            private void ToggleSettingsView()
            {
                if (mainFormRef != null)
                {
                    settingsVisible = !settingsVisible;
                    if (settingsVisible)
                    {
                        mainFormRef.ClientSize = new Size(mainFormRef.ClientSize.Width, this.openedHeight);
                    }
                    else
                    {
                        mainFormRef.ClientSize = new Size(mainFormRef.ClientSize.Width, this.closedHeight);
                    }
                    this.Invalidate();
                }
            }
            protected override void OnMouseEnter(EventArgs e)
            {
                base.OnMouseEnter(e);
                toggleHover();
            }           
            protected override void OnMouseLeave(EventArgs e)
            {
                base.OnMouseLeave(e);
                toggleHover();
            }
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                e.Graphics.Clear(this.BackColor);
                Color lineColor = Color.Empty;
                if (mouseIsHover)
                {
                    lineColor = Color.FromArgb(255, 255, 255, 255);
                }
                else
                {
                    lineColor = Color.FromArgb(100, 255, 255, 255);
                }
                using (Pen myPen = new Pen(lineColor, thickness))
                {
                    int yPos = Convert.ToInt32(settingsVisible) * (this.Height - thickness) + ((!settingsVisible) ? MarginTop : -1 * MarginBottom);
                    Point[] myPoints = {new Point(thickness+MarginLeft, yPos),
                                    new Point(this.Width/2, Convert.ToInt32(!settingsVisible) * (this.Height-thickness) + ((settingsVisible) ? MarginTop : -1*MarginBottom)),
                                   new Point(this.Width-thickness-MarginRight, yPos)};
                    e.Graphics.DrawLines(myPen, myPoints);
                }              
            }
        }
       
    }
}